diff --git a/CHANGELOG.MD b/CHANGELOG.MD new file mode 100644 index 0000000..7d58e4d --- /dev/null +++ b/CHANGELOG.MD @@ -0,0 +1,117 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.31.2] - 2021-02-06 + +### Added +- Id to MeshFrame +- Non textured rendering (RGBA only) + +### Changed +- Moved color from mesh to mesh material. +- OBJ Loader refactor +- Logic of loadFrom() +- Migrated to GCC9 (valid with latest PS2SDK) + +### Removed +- Removed MeshId from TextureLink, TextureRepository + +## [1.29.1] - 2020-12-27 +### Added +- Created libpacket2 in PS2SDK +- Dolphin sample +- 2D support (Sprite class) +- Alpha blending (transparency) +- PNG support +- ADPCM support in audio class +- AudioFinish event in audio class +- BoundingBox class +- A lot of useful funcs in Matrix class +- Mock of file service +- Array mode to draw() (highly optimized for small meshes) +- VCLPP - Usage of VU1 Preprocessor + +### Changed +- Project setup (makefile mostly) +- Readme +- Switched into libpacket2 in `vifsender` and `gifsender` +- Timer class refactor +- Engine base refactor +- MeshTexture into Texture +- Refactored floors sample +- Refactored Audio class +- Fixed Path 3 lighting +- Refactored, optimized math classes (vector, matrix..) +- Cleanup in camera base +- Refactored Path 3 and Path 1 rendering +- Synchronization functions (`renderer->waitForRender()`) +- BMP class refactor +- Dff Loader refactor +- Optimized rendering data preparation + +### Removed +- Ari sample +- VU1 class + +## [1.1.0] - 2020-11-03 +### Added +- A lot of useful functions to Mesh class +- MeshFrame class +- MeshMaterial class +- MeshTexture class +- TextureLink struct +- Texture wrapping settings +- TextureRepository class +- PRINT_ERR() +- Ari sample + +### Changed +- Project setup (gitignore etc.) +- Readme +- DFF loader refactor +- OBJ loader refactor +- MD2 loader refactor +- 3D data classes refactor (one interface for all) +- Rendering refactor + +### Removed +- MeshSpec class +- Texture class +- Md2Model class +- ObjModel class +- DffModel class + +## [1.0.0] - 2020-10-28 +### Added +- Project setup (gitignore etc.) +- License +- Readme +- BMP support +- DFF support +- MD2 support +- OBJ support +- Animation support +- Engine base +- AudioListener class +- Rendering base +- Path 1 renderer (VU1) +- Path 3 renderer (GIF) +- Math classes (matrix, vector, plane..) +- Audio support (bg song only) +- Camera base +- Base lighting support (bugged) for Path 3 +- Pad support +- EE Timer +- Math class +- String class +- Mesh class with AABB +- Makefile +- Primitive floors sample + +[1.31.2]: https://github.com/h4570/tyra/compare/v1.29.1-alpha...v1.31.2-alpha +[1.29.1]: https://github.com/h4570/tyra/compare/1.1.0...v1.29.1-alpha +[1.1.0]: https://github.com/h4570/tyra/compare/1.0.0...1.1.0 +[1.0.0]: https://github.com/h4570/tyra/compare/1.0.0 diff --git a/README.MD b/README.MD index 972e0cf..f3c2777 100644 --- a/README.MD +++ b/README.MD @@ -1,19 +1,22 @@ [![Contributors][contributors-shield]][contributors-url] -[![MIT License][license-shield]][license-url] -PS2-Scene [![Discord](https://img.shields.io/discord/652861436992946216?logo=discord)](https://discord.gg/7dCr6ThSN5) +[![MIT License][license-shield]][license-url] +[![Discord](https://img.shields.io/badge/discord-Tyra-brightgreen?logo=discord)](https://discord.gg/NhhTmg3Gm5) +[![Discord](https://img.shields.io/badge/discord-PS2--Scene-brightgreen?logo=discord)](https://discord.gg/7dCr6ThSN5)

- Logo + Logo -

Tyra alpha 1.1.0

+

Tyra - alpha 1.31.2

- Open source renderer and game engine for PS2 (PlayStation 2™). + Open source game engine for PlayStation 2™
- View Demo (soon) » + Dolphin sample » +   + Floors sample »

Report Bug @@ -27,95 +30,79 @@ PS2-Scene [![Discord](https://img.shields.io/discord/652861436992946216?logo=dis * [About the Project](#about-the-project) * [Samples](#samples) * [About project](#about-project) - * [Acronyms](#acronyms) * [Tyra features](#tyra-features) - * [Built With](#built-with) + * [Branches](#branches) * [Getting Started](#getting-started) - * [Prerequisites](#prerequisites) * [Installation](#installation) + * [Prerequisites](#prerequisites) * [Roadmap](#roadmap) +* [Tyra team](#tyra-team) * [Contributing](#contributing) * [License](#license) -* [Contact](#contact) +* [Built With](#built-with) +* [Acronyms](#acronyms) * [Thanks](#thanks) ## About The Project -sample +sample ### Samples +* [Dolphin](https://github.com/h4570/tyra/tree/master/src/samples/dolphin) * [Floors](https://github.com/h4570/tyra/tree/master/src/samples/floors) -* [Ari (WIP)](https://github.com/h4570/tyra/tree/master/src/samples/ari) - -### Contributors wanted -#### I will be grateful for any help, Discord: h4570#3402 ### About project -Goal of Tyra project is to provide simple API for PS2 (PlayStation 2™) game creation. So you can just run PS2 emulator, grab your .obj file, and put it into live in a seconds. Project is on early stage, so a lot of stuff is changing from release to release. +Goal of Tyra project is to provide simple API for PS2 game creation, so you can just run PS2 emulator, grab .obj file, and put it into live in a seconds. Project is on alpha stage, so keep in mind that there are many things to be done and to fix. YouTube tutorials soon! -**Why PS2 game dev is so different?** Raw PS2 development can be a big challenge. PS2 it's pretty low-level and there are a lot of stuff that you must do from scratch. -Tyra takes care for you, and rendering, coprocessors communication and many more low-level stuff is already done. - -### Acronyms -* EE (Emotion Engine) - whole set of processors and subsystems that make up the PlayStation 2 -* GS (Graphic synthesizer) - configurable rasterizer and texture mapper. Has only 2MB~ memory for textures, but for the opposite have very high transfer rate, so you can switch textures in the blink -* VU0 - programmable (ASM) vector processor that is accessed by inline assembly code injected into C program. -* VU1 - programmable (ASM) vector processor, which is similar to vertex shader. Accessed via DMA. -* IOP - I/O processor which enables access to peripheral devices, such the game controller +**Why Tyra is needed?** Raw PS2 development can be a big challenge. PS2 it's pretty low-level and there are a lot of stuff that you must do from scratch. +Tyra takes care for you, and rendering, coprocessors communication, synchronization and many more low-level stuff is already done. ### Tyra features -* VU1 rendering (PATH 1), double-buffered -* GIF rendering (PATH 3), double-buffered +* 3D support - VU1 "Path 1 rendering" +* 2D support - PNG & BMP * Frustum culling, backface culling * OpenGL adaptions: Perspective projection, lookAt camera -* Texture support (.bmp loader) +* Texture support - .bmp and png * Mesh loaders: ".obj", ".dff" (RenderWare, GTA:SA) and ".md2" (Quake II) * Threading support -* Lighting support (now PATH3 only) -* Animation support -* Audio support +* Animation support for obj and md2 +* Audio support - .wav and .adpcm * Pad support -* TODO: physics, ADPCM and many more! -### Built With - -* [PS2SDK](https://github.com/ps2dev/ps2sdk) +### Branches +* Master - monthly releases - tested on PS2 & PCSX2. +* Develop - daily builds - can be unstable. ## Getting Started -To get a local copy up and running follow these simple steps. -YouTube tutorials soon! +### Installation [![Discord](https://img.shields.io/badge/discord-Tyra-brightgreen?logo=discord)](https://discord.gg/NhhTmg3Gm5) +In our Discord channel, there is detailed tutorial which will help you with setting up the all environment - starting from installing dependencies and ending on emulator setup or intellisense. ### Prerequisites -This is an example of how to list things you need to use the software and how to install them. +This is an example of how to list things you need to use the software. * PS2 DEV environment - [PS2DEV](https://github.com/ps2dev/ps2dev) -* At least #674b6f4 PS2SDK (01.12.2020) - [PS2SDK](https://github.com/ps2dev/ps2sdk) +* At least #e8e9edb PS2SDK (06.02.2021) - [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 +* BMP loader needs some polishing so be sure that you exporting BMP with 24bit: RGB888 and without 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. +* If you want to use your own .obj file, please check "triangulate faces" in blender. PS2 is supporting only triangle primitive type. ## Roadmap -### Roadmap moved to github kanban: -[https://github.com/h4570/tyra/projects/1](https://github.com/h4570/tyra/projects/1) +### Roadmap for next master release: +[Next release roadmap](https://github.com/h4570/tyra/projects/4) +## Tyra team + +Sandro Sobczyński - sandro.sobczynski@gmail.com +[![LinkedIn][linkedin-shield]](https://linkedin.com/in/sandro-sobczyński-28820b15a) +Michał Mostowik - mostek3pl@gmail.com +[![LinkedIn][linkedin-shield]](https://www.linkedin.com/in/notfoxar) See the [open issues](https://github.com/h4570/tyra/issues) for a list of proposed features (and known issues). @@ -133,26 +120,38 @@ Contributions are what make the open source community such an amazing place to b Distributed under the Apache License 2.0 License. See `LICENSE` for more information. -## Contact +## Built With -Sandro Sobczyński - sandro.sobczynski@gmail.com -[![LinkedIn][linkedin-shield]][linkedin-url] +* [PS2SDK](https://github.com/ps2dev/ps2sdk) + +### Acronyms +* EE (Emotion Engine) - whole set of processors and subsystems that make up the PlayStation 2 +* GS (Graphic synthesizer) - configurable rasterizer and texture mapper. Has only 2MB~ memory for textures, but for the opposite have very high transfer rate, so you can switch textures in the blink +* VU0 - programmable (ASM) vector processor that is accessed by inline assembly code injected into C program. +* VU1 - programmable (ASM) vector processor, which is similar to vertex shader. Accessed via DMA. +* IOP - I/O processor which enables access to peripheral devices, such the game controller ## Thanks Without these guys, everything would be harder: -* Dr Henry Fortuna - Abertay University (code sources) -* Lukasz D.K. (huge archive of PS2 stuff) -* Guilherme Lampert - PlayStation London (code sources) -* Jesper Svennevid, Daniel Collin - Microcode (openvcl, code samples) -* Whole PS2SDK/PS2Scene team +* Dr Henry Fortuna - for code sources +* Rick Gaiser - for help and new GCC! +* Lukasz D.K. - for huge archive of PS2 stuff +* Guilherme Lampert - for code sources +* Jesper Svennevid, Daniel Collin - for openvcl's code samples +* Whole PS2DEV team +* Manieq - for nice splash screens! * And so many other guys. Thanks! Project Link: [https://github.com/h4570/tyra](https://github.com/h4570/tyra) + +
+ + Logo + [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 diff --git a/src/engine/Makefile b/src/engine/Makefile index 78c621f..949c572 100644 --- a/src/engine/Makefile +++ b/src/engine/Makefile @@ -35,8 +35,10 @@ all: $(EE_OBJS) ar rcs $(LIB_NAME) $(EE_OBJS) rm -f $(EE_OBJS) -# https://github.com/microsoft/wsl/issues/2468#issuecomment-374904520 -#%.vsm: %.vcl # sudo service binfmt-support start +#%.vcl: %.vclpp +# $(EE_VCLPP) $< $@ + +#%.vsm: %.vcl # $(EE_VCL) $< >> $@ %.o: %.vsm diff --git a/src/engine/Makefile.pref b/src/engine/Makefile.pref index 389166e..24f0306 100644 --- a/src/engine/Makefile.pref +++ b/src/engine/Makefile.pref @@ -1,10 +1,11 @@ -EE_LIBS := $(EE_LIBS) -ldraw -lgraph -lmath3d -lpacket -ldma -lpacket2 -lpad -laudsrv -lc -lstdc++ -lpng -lz +EE_LIBS := $(EE_LIBS) -ldraw -lcdvd -lgraph -lmath3d -lpacket -ldma -lpacket2 -lpad -laudsrv -lc -lstdc++ -lpng -lz EE_INCS := -I$(TYRA_DIR)/include -I$(PS2SDK)/ports/include $(EE_INCS) EE_LDFLAGS := -L$(PS2SDK)/ports/lib -L$(TYRA_DIR) $(EE_LDFLAGS) -EE_CFLAGS := -DHAVE_LIBPNG -DHAVE_ZLIB $(EE_CFLAGS) -EE_CXXFLAGS := -DHAVE_LIBPNG -DHAVE_ZLIB $(EE_CXXFLAGS) +EE_CFLAGS := -DHAVE_LIBPNG -D_XCDVD -DHAVE_ZLIB $(EE_CFLAGS) +EE_CXXFLAGS := -DHAVE_LIBPNG -D_XCDVD -DHAVE_ZLIB $(EE_CXXFLAGS) EE_DVP = dvp-as EE_VCL = vcl +EE_VCLPP = vclpp LIB_NAME = libtyra.a include $(PS2SDK)/samples/Makefile.pref diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 4a604ba..65a111e 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -41,13 +41,13 @@ Engine::~Engine() {} 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; + screen.aspectRatio = screen.width / screen.height; + screen.projectionScale = 4096.0F; // PS2 have 4k drawing area } void Engine::init(Game *t_game, u32 t_gifPacketSize) @@ -77,8 +77,9 @@ void Engine::firePS2() { SifInitRpc(0); srand(time(NULL)); - fileService.startThread(); - audio.startThread(&fileService); + // fileService.startThread(); + // audio.startThread(&fileService); + audio.startThread(NULL); isInitialized = 0; mainThreadId = GetThreadId(); } diff --git a/src/engine/include/engine.hpp b/src/engine/include/engine.hpp index 5f10f65..17be5a8 100644 --- a/src/engine/include/engine.hpp +++ b/src/engine/include/engine.hpp @@ -32,7 +32,7 @@ public: void init(Game *t_game, u32 t_gifPacketSize); void setDefaultScreen(); Renderer *renderer; - FileService fileService; + // FileService fileService; Audio audio; ScreenSettings screen; Pad pad; diff --git a/src/engine/include/models/bounding_box.hpp b/src/engine/include/models/bounding_box.hpp index cab4a9b..a2f6c44 100644 --- a/src/engine/include/models/bounding_box.hpp +++ b/src/engine/include/models/bounding_box.hpp @@ -91,4 +91,4 @@ private: BoundingBoxFace _bottomFace; }; -#endif \ No newline at end of file +#endif diff --git a/src/engine/include/models/math/matrix.hpp b/src/engine/include/models/math/matrix.hpp index 5e13bd7..46b5140 100644 --- a/src/engine/include/models/math/matrix.hpp +++ b/src/engine/include/models/math/matrix.hpp @@ -13,79 +13,174 @@ #include "vector3.hpp" #include "../screen_settings.hpp" +#include -/** https://en.wikipedia.org/wiki/Matrix_(mathematics) */ +/** 4x4 Matrix class. */ class Matrix { public: - float data[16]; + float data[16] __attribute__((aligned(64))); - 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*(const Matrix &v); - void operator*=(const Matrix &v); + // ---- + // Constructors/Destructors + // ---- + + /** Create empty matrix. */ Matrix(); - ~Matrix(); - void lookAt(Vector3 &t_up, Vector3 &t_position, Vector3 &t_target); + /** + * Create identity/empty matrix. + * @param t_do_identity Identity matrix if true, random matrix values otherwise + */ + Matrix(const u8 &t_do_identity) + { + if (t_do_identity) + identity(); + } + + /** Init matrix with given values. */ + Matrix(const float &m11, const float &m12, const float &m13, const float &m14, + const float &m21, const float &m22, const float &m23, const float &m24, + const float &m31, const float &m32, const float &m33, const float &m34, + const float &m41, const float &m42, const float &m43, const float &m44); + + /** Init matrix with other matrix values. */ + Matrix(const Matrix &v) { memcpy(data, v.data, 16 * sizeof(float)); } + + // ---- + // Operators + // ---- + + Vector3 operator*(const Vector3 &v) const; + + Matrix operator*(const Matrix &v) const + { + Matrix result; + cross(result.data, this->data, v.data); + return result; + } + + inline void operator*=(const Matrix &v) { cross(this->data, this->data, v.data); } + + float &operator[](const u8 &t_index) { return data[t_index]; } + + // ---- + // Functions + // ---- + + /** + * 1 0 0 0 + * 0 1 0 0 + * 0 0 1 0 + * 0 0 0 1 + */ void identity(); + + /** + * 1 0 0 0 + * 0 1 0 0 + * 0 0 1 0 + * 0 0 0 1 + */ inline void unit() { identity(); }; - // Translation - - void translate(const Vector3 &t_val); - - inline void translation(const Vector3 &t_val) + /** Translate matrix. */ + inline void translate(const Vector3 &t_val) { - identity(); - translate(t_val); - } - - // Rotation - - void rotateX(const float &t_radians); - void rotateY(const float &t_radians); - void rotateZ(const float &t_radians); - - inline void rotationX(const float &t_radians) - { - identity(); - rotateX(t_radians); - } - - inline void rotationY(const float &t_radians) - { - identity(); - rotateY(t_radians); - } - - inline void rotationZ(const float &t_radians) - { - identity(); - rotateZ(t_radians); + Matrix temp = Matrix(true); + temp.translation(t_val); + cross(this->data, temp.data, this->data); } + /** Rotate matrix. */ inline void rotate(const Vector3 &t_val) { - rotateX(t_val.x); - rotateY(t_val.y); - rotateX(t_val.z); + Matrix temp = Matrix(true); + + temp.rotationZ(t_val.z); + cross(this->data, temp.data, this->data); + + temp.identity(); + temp.rotationY(t_val.y); + cross(this->data, temp.data, this->data); + + temp.identity(); + temp.rotationX(t_val.x); + cross(this->data, temp.data, this->data); } - inline void rotation(const Vector3 &t_val) + /** Rotate matrix by X. */ + inline void rotateX(const float &t_radians) { - identity(); - rotate(t_val); + Matrix temp = Matrix(true); + temp.rotationX(t_radians); + cross(this->data, temp.data, this->data); } - // + /** Rotate matrix by Y. */ + inline void rotateY(const float &t_radians) + { + Matrix temp = Matrix(true); + temp.rotationY(t_radians); + cross(this->data, temp.data, this->data); + } - void setPerspective(ScreenSettings &screen); + /** Rotate matrix by Z. */ + inline void rotateZ(const float &t_radians) + { + Matrix temp = Matrix(true); + temp.rotationZ(t_radians); + cross(this->data, temp.data, this->data); + } + + /** Rotate matrix by angle. */ + void rotateByAngle(const float &t_angle, const Vector3 &t_axis) + { + Matrix temp; + temp.rotationByAngle(t_angle, t_axis); + cross(this->data, temp.data, this->data); + } + + /** Scale matrix. */ + void scale(const Vector3 &t_val) + { + Matrix temp = Matrix(true); + temp.setScale(t_val); + cross(this->data, temp.data, this->data); + } + + /** + * Create perspective projection matrix. + * + * Complies with OpenGL standard (gluPerspective). + * @see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml + * @param screen Screen settings + */ + void setPerspective(const ScreenSettings &screen); + + /** + * Create a view matrix that transforms coordinates in + * such a way that the user looks at a target vector + * direction from a position vector. + * + * Complies with OpenGL standard (glLookAt). + * @see https://learnopengl.com/Getting-started/Camera + */ + void lookAt(const Vector3 &t_position, const Vector3 &t_target); + + /** Print matrix (printf). */ const void print() const; + +private: + void rotationX(const float &t_radians); + void rotationY(const float &t_radians); + void rotationZ(const float &t_radians); + void rotationByAngle(const float &t_angle, const Vector3 &t_axis); + void translation(const Vector3 &t_val); + void setScale(const Vector3 &t_val); + void setCamera(const float t_pos[4], const float t_vz[4], const float t_vy[4]); + void cross(float res[16], const float a[16], const float b[16]) const; }; #endif diff --git a/src/engine/include/models/math/vector3.hpp b/src/engine/include/models/math/vector3.hpp index 641f6b1..53939af 100644 --- a/src/engine/include/models/math/vector3.hpp +++ b/src/engine/include/models/math/vector3.hpp @@ -12,6 +12,7 @@ #define _TYRA_VECTOR3_ #include +#include class Math; // Forward definition @@ -20,6 +21,7 @@ class Vector3 { public: + /** This trick will allow use to use vec.x and vex[0] */ union { struct @@ -31,32 +33,91 @@ public: float xyz[3] __attribute__((__aligned__(16))); }; - Vector3(float t_x, float t_y, float t_z); - Vector3(const Vector3 &v); + // ---- + // Constructors/Destructors + // ---- + + /** Create empty vector. */ Vector3(); - ~Vector3(); - Vector3 operator+(Vector3 v); - Vector3 operator-(const Vector3 &v); - Vector3 operator*(Vector3 &v); - Vector3 operator*(const float &t); + /** Create vector with given vector values. */ + Vector3(const Vector3 &t_v) { set(t_v); } + + /** Create vector with given values. */ + Vector3(const float &t_x, const float &t_y, const float &t_z) { set(t_x, t_y, t_z); } + + // ---- + // Operators + // ---- + + Vector3 operator+(const Vector3 &v) const; + Vector3 operator-(const Vector3 &v) const; + /** Also called "cross product" */ + Vector3 operator*(const Vector3 &v) const; + Vector3 operator*(const float &t) const; + Vector3 operator/(const float &t) const; + Vector3 operator-(void) const { return Vector3(-x, -y, -z); } + void operator+=(const Vector3 &t); void operator*=(const 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(const Vector3 &t_min, const Vector3 &t_max) const; - u8 isOnSquare(const Vector3 &t_min, const Vector3 &t_max) const; - float length(); - void normalize(); - void setByLerp(const Vector3 &v1, const Vector3 &v2, const float &t_interp, const float &t_scale); - float innerProduct(Vector3 &v); + // ---- + // Functions + // ---- + + /** Set vector values via VU0. */ void set(const Vector3 &v); - void rotate(const Vector3 &v, u8 inversed = false); + + /** Set vector values. */ void set(const float &t_x, const float &t_y, const float &t_z); - void copy(Vector3 &v); + + /** Also called dot3. */ + float innerProduct(const Vector3 &v) const; + + /** Get vector length */ + float length() const; + + /** Normalize vector. */ + void normalize(); + + /** Returns distance between two vectors */ float distanceTo(const Vector3 &v) const; - const void print() const; + + /** + * Checks intersection with given box + * @param t_min Opposite min vertex (ex. near, left, down vertex of bounding box) + * @param t_max Opposite max vertex (ex. far, right, up vertex of bounding box) + */ + u8 collidesBox(const Vector3 &t_min, const Vector3 &t_max) const + { + 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 if this vector is on given box (this->y >= box.y) + * @param t_min Opposite min vertex (ex. near, left, down vertex of bounding box) + * @param t_max Opposite max vertex (ex. far, right, up vertex of bounding box) + */ + u8 isOnBox(const Vector3 &t_min, const Vector3 &t_max) const + { + 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; + } + + /** Check if given triangle should be backface culled. */ + static u8 shouldBeBackfaceCulled(const Vector3 *t_cameraPos, const Vector3 *t_v0, const Vector3 *t_v1, const Vector3 *t_v2); + + /** + * Set by linear interpolation between two vertices (animation). + * @param t_v1 Before vertex + * @param t_v2 After vertex + * @param t_interp State of interpolation + * @param t_scale Scale + */ + void setByLerp(const Vector3 &t_v1, const Vector3 &t_v2, const float &t_interp, const float &t_scale); + + const void print() const + { + printf("Vector3(%f, %f, %f)\n", x, y, z); + } }; #endif diff --git a/src/engine/include/models/mesh.hpp b/src/engine/include/models/mesh.hpp index 1f9e7ea..64983fa 100644 --- a/src/engine/include/models/mesh.hpp +++ b/src/engine/include/models/mesh.hpp @@ -16,7 +16,6 @@ #include "./texture.hpp" #include "./mesh_frame.hpp" #include -#include #include #include #include "./anim_state.hpp" @@ -43,7 +42,6 @@ public: * When true, mesh materials are not drawn when they are outside of view frustum. */ u8 shouldBeFrustumCulled; - color_t color; clutbuffer_t clut; lod_t lod; @@ -176,6 +174,8 @@ public: void setAnimSpeed(const float &t_value) { animState.speed = t_value; } + const u8 &areFramesAllocated() const { return _areFramesAllocated; }; + /** * Check if this class loaded mesh data first. * Meshes which use loadFrom() method have false there. @@ -207,9 +207,8 @@ private: AnimState animState; MeshFrame *frames; u32 id, framesCount; - u8 _isMother; + u8 _isMother, _areFramesAllocated; Vector3 calc3Vectors[3]; - void setDefaultColor(); void setDefaultLODAndClut(); }; diff --git a/src/engine/include/models/mesh_frame.hpp b/src/engine/include/models/mesh_frame.hpp index cd7c299..48cc772 100644 --- a/src/engine/include/models/mesh_frame.hpp +++ b/src/engine/include/models/mesh_frame.hpp @@ -35,6 +35,12 @@ public: // Getters // ---- + /** + * Auto generated unique Id. + * Core role of this variable is to select correct texture to draw + */ + const u32 &getId() const { return id; }; + const u32 &getVertexCount() const { return vertexCount; }; const u32 &getSTsCount() const { return stsCount; }; const u32 &getNormalsCount() const { return normalsCount; }; @@ -119,12 +125,27 @@ public: // Other // ---- + /** + * Check if this object is mother. + * Mother = object loaded with loadObj(), loadDff().. + * Have all mother data: vertex, st, etc.. + * Non-mother = object loaded with loadFrom(). + * Have reference copy to mother data: vertex, st, etc.. + * + * When you will destruct mother object, all vertex, st data will be deleted. + * When you will destruct non-mother object, all vertex, st data will be NOT deleted. + */ + const u8 &isMother() const { return _isMother; }; + const u8 &areSTsAllocated() const { return _areSTsAllocated; }; const u8 &areVerticesAllocated() const { return _areVerticesAllocated; }; const u8 &areNormalsAllocated() const { return _areNormalsAllocated; }; const u8 &areMaterialsAllocated() const { return _areMaterialsAllocated; }; const u8 &isBoundingBoxCalculated() const { return _isBoundingBoxCalculated; }; + /** Create reference copy (non-mother) */ + void copyFrom(MeshFrame *t_refCopy); + /** Set STs count and allocate memory. */ void allocateSTs(const u32 &t_val); @@ -146,12 +167,13 @@ public: private: BoundingBox *boundingBoxObj; - u8 _areSTsAllocated, + u8 _isMother, + _areSTsAllocated, _areVerticesAllocated, _areNormalsAllocated, _areMaterialsAllocated, _isBoundingBoxCalculated; - u32 vertexCount, stsCount, normalsCount, materialsCount; + u32 vertexCount, stsCount, normalsCount, materialsCount, id; MeshMaterial *materials; Point __attribute__((aligned(16))) * sts; Vector3 __attribute__((aligned(16))) * vertices, *normals; diff --git a/src/engine/include/models/mesh_material.hpp b/src/engine/include/models/mesh_material.hpp index 3ba2621..03bbeeb 100644 --- a/src/engine/include/models/mesh_material.hpp +++ b/src/engine/include/models/mesh_material.hpp @@ -12,6 +12,7 @@ #define _TYRA_MESH_MATERIAL_ #include +#include #include "bounding_box.hpp" #include "./math/vector3.hpp" #include "./math/plane.hpp" @@ -29,6 +30,8 @@ public: MeshMaterial(); ~MeshMaterial(); + color_t color; + // ---- // Getters // ---- @@ -104,11 +107,43 @@ public: /** Set material name. */ void setName(char *t_val); + /** + * Do not call this method unless you know what you do. + * Should be called by data loader. + */ + void setSTsPresent(const u8 &b) { _areSTsPresent = b; }; + + /** + * Do not call this method unless you know what you do. + * Should be called by data loader. + */ + void setNormalsPresent(const u8 &b) { _areNormalsPresent = b; }; + // ---- // Other // ---- + const u8 &areSTsPresent() const { return _areSTsPresent; }; + + const u8 &areNormalsPresent() const { return _areNormalsPresent; }; + + /** Create reference copy (non-mother) */ + void copyFrom(MeshMaterial *t_refCopy); + const u8 &isNameSet() const { return _isNameSet; }; + + /** + * Check if this object is mother. + * Mother = object loaded with loadObj(), loadDff().. + * Have all mother data: vertex faces, st faces, etc.. + * Non-mother = object loaded with loadFrom(). + * Have reference copy to mother data: vertex faces, st faces, etc.. + * + * When you will destruct mother object, all faces data will be deleted. + * When you will destruct non-mother object, all faces data will be NOT deleted. + */ + const u8 &isMother() const { return _isMother; }; + const u8 &areFacesAllocated() const { return _areFacesAllocated; }; /** Set faces count and allocate memory. */ @@ -125,10 +160,16 @@ public: u8 isInFrustum(Plane *t_frustumPlanes, const Vector3 &position); private: + void setDefaultColor(); BoundingBox *boundingBoxObj; u32 facesCount, id; u32 *vertexFaces, *stFaces, *normalFaces; - u8 _isNameSet, _areFacesAllocated, _isBoundingBoxCalculated; + u8 _isMother, + _isNameSet, + _areFacesAllocated, + _isBoundingBoxCalculated, + _areSTsPresent, + _areNormalsPresent; char *name; }; diff --git a/src/engine/include/models/render_data.hpp b/src/engine/include/models/render_data.hpp index 4045fd8..f4a89c7 100644 --- a/src/engine/include/models/render_data.hpp +++ b/src/engine/include/models/render_data.hpp @@ -22,10 +22,18 @@ struct RenderData { LightBulb *bulbs; u16 bulbsCount; - /** Camera (lookAt) */ - Matrix *worldView; - /** Perspective projection */ - Matrix *perspective; + /** + * Camera matrix (glLookAt) + * OpenGL name: View + * Sony name: World view + */ + Matrix *view; + /** + * Projection matrix (glPerspective) + * OpenGL name: Projection + * Sony name: View screen + */ + Matrix *projection; Vector3 *cameraPosition; Plane *frustumPlanes; prim_t *prim; diff --git a/src/engine/include/models/texture.hpp b/src/engine/include/models/texture.hpp index 0b9aaaf..470c0b1 100644 --- a/src/engine/include/models/texture.hpp +++ b/src/engine/include/models/texture.hpp @@ -83,21 +83,18 @@ public: /** * Returns index of link. * -1 if not found. + * @param t_id + * For 3D: Mesh material id. + * For 2D: Sprite id. */ - const s32 getIndexOfLink(const u32 &t_meshId, const u32 &t_materialId) const + const s32 getIndexOfLink(const u32 &t_id) const { for (u32 i = 0; i < texLinks.size(); i++) - if (texLinks[i].materialId == t_materialId && texLinks[i].meshOrSpriteId == t_meshId) + if (texLinks[i].id == t_id) return i; return -1; }; - /** - * Returns index of link. - * -1 if not found. - */ - inline const s32 getIndexOfLink(const u32 &t_spriteId) const { return getIndexOfLink(t_spriteId, 0); }; - // ---- // Setters // ---- @@ -144,18 +141,15 @@ public: const u8 &isSizeSet() const { return _isSizeSet; }; - const u8 isLinkedWith(const u32 &t_meshId, const u32 &t_materialId) const + /** + * Check if texture is linked with Mesh/Sprite. + * @param t_id + * For 3D: Mesh material id. + * For 2D: Sprite id. + */ + const u8 isLinkedWith(const u32 &t_id) const { - s32 index = getIndexOfLink(t_meshId, t_materialId); - if (index != -1) - return true; - else - return false; - }; - - const u8 isLinkedWith(const u32 &t_spriteId) const - { - s32 index = getIndexOfLink(t_spriteId); + s32 index = getIndexOfLink(t_id); if (index != -1) return true; else @@ -164,18 +158,15 @@ public: void removeLinkByIndex(const u32 &t_index) { texLinks.erase(texLinks.begin() + t_index); } - void removeLinkBySprite(const u32 &t_spriteId) + /** + * Remove texture link with given Mesh/Sprite. + * @param t_id + * For 3D: Mesh material id. + * For 2D: Sprite id. + */ + void removeLinkById(const u32 &t_id) { - s32 index = getIndexOfLink(t_spriteId); - if (index != -1) - removeLinkByIndex(index); - else - PRINT_ERR("Cant remove link, because it was not found!"); - } - - void removeLinkByMesh(const u32 &t_meshId, const u32 &t_materialId) - { - s32 index = getIndexOfLink(t_meshId, t_materialId); + s32 index = getIndexOfLink(t_id); if (index != -1) removeLinkByIndex(index); else diff --git a/src/engine/include/models/texture_link.hpp b/src/engine/include/models/texture_link.hpp index 75c24b7..687c9c0 100644 --- a/src/engine/include/models/texture_link.hpp +++ b/src/engine/include/models/texture_link.hpp @@ -15,10 +15,11 @@ struct TextureLink { - /** Mesh id or sprite id */ - u32 meshOrSpriteId; - /** Mesh material id or 0 if is sprite */ - u32 materialId; + /** + * For 3D: Mesh material id. + * For 2D: Sprite id. + */ + u32 id; }; #endif diff --git a/src/engine/include/modules/audio.hpp b/src/engine/include/modules/audio.hpp index ea1dfe2..1899cd7 100644 --- a/src/engine/include/modules/audio.hpp +++ b/src/engine/include/modules/audio.hpp @@ -126,7 +126,8 @@ public: private: u8 songLoaded, volume, realVolume, songPlaying, songInLoop, songFinished; - std::vector songListeners; + u8 hack; // TODO + std::vector songListeners; FILE *wav; audsrv_fmt_t format; FileService *fileService; diff --git a/src/engine/include/modules/camera_base.hpp b/src/engine/include/modules/camera_base.hpp index 342acc7..b74ff89 100644 --- a/src/engine/include/modules/camera_base.hpp +++ b/src/engine/include/modules/camera_base.hpp @@ -21,7 +21,7 @@ class CameraBase { public: - CameraBase(ScreenSettings *t_screen, Vector3 *t_position, Vector3 *t_up); + CameraBase(ScreenSettings *t_screen, Vector3 *t_position); virtual ~CameraBase(){}; /** @@ -31,10 +31,10 @@ public: Plane planes[6]; /** - * Projection matrix + * View matrix * Set by lookAt() method. */ - Matrix worldView; + Matrix view; protected: /** Pointer to screen settings */ @@ -42,7 +42,7 @@ protected: /** * Adaption of OpenGL lookAt camera. - * Calculates worldView matrix and update frustum planes + * Calculates view matrix and update frustum planes * Should be called every frame. */ void lookAt(Vector3 &t_target); @@ -56,9 +56,10 @@ protected: void updatePlanes(Vector3 t_target); private: - Vector3 *p_position, *p_up; + Vector3 *p_position; float farPlaneDist, nearPlaneDist, nearHeight, nearWidth, farHeight, farWidth; Vector3 ftl, ftr, fbl, fbr, ntl, ntr, nbl, nbr; + Vector3 up; // always 0.0F, 1.0F, 0.0F }; #endif diff --git a/src/engine/include/modules/gif_sender.hpp b/src/engine/include/modules/gif_sender.hpp index 0c7646b..baeee9c 100644 --- a/src/engine/include/modules/gif_sender.hpp +++ b/src/engine/include/modules/gif_sender.hpp @@ -34,7 +34,7 @@ public: ~GifSender(); void initPacket(u8 context); - void addObject(RenderData *t_renderData, Mesh &t_mesh, u32 vertexCount, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, LightBulb *t_bulbs, u16 t_bulbsCount, texbuffer_t *textureBuffer); + void addObject(RenderData *t_renderData, Mesh &t_mesh, u32 vertexCount, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, LightBulb *t_bulbs, u16 t_bulbsCount, texbuffer_t *textureBuffer, color_t *t_color); void addClear(zbuffer_t *t_zBuffer, color_t *t_rgb); void sendPacket(); void sendClear(zbuffer_t *t_zBuffer, color_t *t_rgb); @@ -54,7 +54,7 @@ private: float halfScreenW, halfScreenH; MATRIX localWorld, localScreen, localLight; - void calc3DObject(Matrix t_perspective, Mesh &t_mesh, u32 vertexCount, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, RenderData *t_renderData, LightBulb *t_bulbs, u16 t_bulbsCount); + void calc3DObject(Matrix t_perspective, Mesh &t_mesh, u32 vertexCount, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, RenderData *t_renderData, LightBulb *t_bulbs, u16 t_bulbsCount, color_t *t_color); void convertCalcs(u32 t_vertCount, VECTOR *t_vertices, VECTOR *t_colors, VECTOR *t_sts, color_t &t_color); void addCurrentCalcs(u32 &t_vertexCount); }; diff --git a/src/engine/include/modules/renderer.hpp b/src/engine/include/modules/renderer.hpp index d2cdb76..9066081 100644 --- a/src/engine/include/modules/renderer.hpp +++ b/src/engine/include/modules/renderer.hpp @@ -13,6 +13,8 @@ #include #include +#include +#include #include #include "gif_sender.hpp" #include "vif_sender.hpp" @@ -39,60 +41,87 @@ public: void enableVSync() { isVSyncEnabled = true; } void disableVSync() { isVSyncEnabled = false; } - /// --- Draw: PATH3 + /** Reset draw wait flag. */ + inline void resetWaitFlag() + { + *GS_REG_CSR |= 2; + } + /** Checks if draw wait flag is set */ + inline u8 isWaitFlagSet() const + { + return *GS_REG_CSR & 2; + } + + /** Waits for draw wait flag and reset it. */ + inline void waitForRender() + { + while (!isWaitFlagSet()) + ; + resetWaitFlag(); + } + + /** 2D draw. */ void draw(Sprite &t_sprite); - /** - * Draw many meshes with lighting information. - * Slowest way of rendering (PATH 3, using EE and GIF). - * NOTICE: Animation supported, lighting supported - */ - void drawByPath3(Mesh *t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount); + /// --- OBSOLETE - /** - * Draw mesh with lighting information. - * Slowest way of rendering (PATH 3, using EE and GIF). - * NOTICE: Animation supported, lighting supported - */ - void drawByPath3(Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount); + // /** + // * WARNING: THIS FUNC CAUSE VISUAL ARTIFACTS! + // * Draw many meshes with lighting information. + // * Slowest way of rendering (PATH 3, using EE and GIF). + // * NOTICE: Animation supported, lighting supported + // */ + // void drawByPath3(Mesh *t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount); - /** - * Draw many meshes without lighting information. - * Slowest way of rendering (PATH 3, using EE and GIF). - * NOTICE: Animation supported, lighting supported - */ - void drawByPath3(Mesh *t_meshes, u16 t_amount); + // /** + // * WARNING: THIS FUNC CAUSE VISUAL ARTIFACTS! + // * Draw mesh with lighting information. + // * Slowest way of rendering (PATH 3, using EE and GIF). + // * NOTICE: Animation supported, lighting supported + // */ + // void drawByPath3(Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount); - /** - * Draw mesh without lighting information. - * Slowest way of rendering (PATH 3, using EE and GIF). - * NOTICE: Animation supported, lighting supported - */ - void drawByPath3(Mesh &t_mesh); + // /** + // * WARNING: THIS FUNC CAUSE VISUAL ARTIFACTS! + // * Draw many meshes without lighting information. + // * Slowest way of rendering (PATH 3, using EE and GIF). + // * NOTICE: Animation supported, lighting supported + // */ + // void drawByPath3(Mesh *t_meshes, u16 t_amount); + + // /** + // * WARNING: THIS FUNC CAUSE VISUAL ARTIFACTS! + // * Draw mesh without lighting information. + // * Slowest way of rendering (PATH 3, using EE and GIF). + // * NOTICE: Animation supported, lighting supported + // */ + // void drawByPath3(Mesh &t_mesh); /// --- Draw: PATH1 /** - * Draw many meshes with lighting information. + * Draw many meshes with lighting information. + * Draw in array mode, can be A LOT faster than for looping! * Fastest way of rendering (PATH 1, using VU1). * NOTICE: Animation supported, lighting NOT supported (at this moment) */ - void draw(Mesh *t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount); + void draw(Mesh **t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount); /** - * Draw mesh with lighting information. - * Fastest way of rendering (PATH 1, using VU1). + * Draw mesh with lighting information. + * Fastest way of rendering (PATH 1, using VU1). * NOTICE: Animation supported, lighting NOT supported (at this moment) */ void draw(Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount); /** - * Draw many meshes without lighting information. - * Fastest way of rendering (PATH 1, using VU1). + * Draw many meshes without lighting information. + * Draw in array mode, can be A LOT faster than for looping! + * Fastest way of rendering (PATH 1, using VU1). * NOTICE: Animation supported, lighting NOT supported (at this moment) */ - void draw(Mesh *t_meshes, u16 t_amount); + void draw(Mesh **t_meshes, u16 t_amount); /** * Draw mesh without lighting information. @@ -125,7 +154,7 @@ private: void flipBuffers(); void beginFrameIfNeeded(); u8 isFrameEmpty; - Matrix perspective; + Matrix perspective, camRotation; Light light; RenderData renderData; TextureRepository textureRepo; @@ -134,8 +163,8 @@ private: VifSender *vifSender; packet2_t *flipPacket; color_t worldColor; - void allocateBuffers(float t_screenW, float t_screenH); - void initDrawingEnv(float t_screenW, float t_screenH); + void allocateBuffers(int t_screenW, int t_screenH); + void initDrawingEnv(); void setPrim(); }; diff --git a/src/engine/include/modules/texture_repository.hpp b/src/engine/include/modules/texture_repository.hpp index b3e29ac..67cd672 100644 --- a/src/engine/include/modules/texture_repository.hpp +++ b/src/engine/include/modules/texture_repository.hpp @@ -45,23 +45,14 @@ public: /** * Returns single texture. * NULL if not found. + * @param t_id + * For 3D: Mesh material id. + * For 2D: Sprite id. */ - Texture *getBySprite(const u32 &t_spriteId) + Texture *getBySpriteOrMesh(const u32 &t_id) { for (u32 i = 0; i < textures.size(); i++) - if (textures[i]->isLinkedWith(t_spriteId)) - return textures[i]; - return NULL; - } - - /** - * Returns single texture. - * NULL if not found. - */ - Texture *getByMesh(const u32 &t_meshId, const u32 &t_materialId) - { - for (u32 i = 0; i < textures.size(); i++) - if (textures[i]->isLinkedWith(t_meshId, t_materialId)) + if (textures[i]->isLinkedWith(t_id)) return textures[i]; return NULL; } diff --git a/src/engine/include/modules/vif_sender.hpp b/src/engine/include/modules/vif_sender.hpp index a3e1e36..65020ab 100644 --- a/src/engine/include/modules/vif_sender.hpp +++ b/src/engine/include/modules/vif_sender.hpp @@ -29,18 +29,33 @@ public: ~VifSender(); // TODO refactor - void drawMesh(RenderData *t_renderData, Matrix t_perspective, u32 vertCount2, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount, texbuffer_t *textureBuffer); - void sendMatrices(const RenderData &t_renderData, const Vector3 &t_position, const Vector3 &t_rotation); + void drawMesh(RenderData *t_renderData, Matrix t_perspective, u32 vertCount2, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount, texbuffer_t *textureBuffer, color_t *t_color, u8 t_rgbaOnly); + void calcMatrix(const RenderData &t_renderData, const Vector3 &t_position, const Vector3 &t_rotation); + void drawTheSameWithOtherMatrices(const RenderData &t_renderData, Mesh **t_meshes, const u32 &t_skip, const u32 &t_count); + void enableWait() { isDrawWaitEnabled = true; } + void disableWait() { isDrawWaitEnabled = false; } private: + u32 lastVertCount; // needed for drawTheSameWithOtherMatrices() + u8 isLastRGBAOnly; // needed for drawTheSameWithOtherMatrices() + u8 isDrawWaitEnabled; Light *light; void uploadMicroProgram(); - void setDoubleBuffer(); - void drawVertices(Mesh &t_mesh, u32 t_start, u32 t_end, VECTOR *t_vertices, VECTOR *t_coordinates, prim_t *t_prim, texbuffer_t *textureBuffer); + void setDoubleBufferAddStaticData(); + void drawVertices(Mesh &t_mesh, u32 t_start, u32 t_end, VECTOR *t_vertices, VECTOR *t_coordinates, prim_t *t_prim, texbuffer_t *t_textureBuffer, u8 t_addDrawWait, color_t *t_color, u8 t_rgbaOnly); packet2_t *packets[2] __attribute__((aligned(64))); packet2_t *currPacket; + /** + * OpenGL name: Model + * Sony name: local world + */ + Matrix model; + /** + * OpenGL name: ModelViewProjection + * Sony name: local screen + */ + Matrix modelViewProj; u8 context; - packet2_t *matricesPacket __attribute__((aligned(64))); VECTOR position, rotation; u32 vertCount; }; diff --git a/src/engine/include/utils/math.hpp b/src/engine/include/utils/math.hpp index 3218047..5e97299 100644 --- a/src/engine/include/utils/math.hpp +++ b/src/engine/include/utils/math.hpp @@ -14,6 +14,7 @@ #include #include #include "../models/math/vector3.hpp" +#include class Vector3; // Forward definition @@ -24,16 +25,15 @@ class Math { public: - const static float HALF_ANG2RAD = 3.14159265358979323846F / 360.0F; - const static float ANG2RAD = 3.14159265358979323846F / 180.0F; - const static float PI = 3.1415926535897932384626433832795F; - const static float HALF_PI = 1.5707963267948966192313216916398F; + constexpr static float HALF_ANG2RAD = 3.14159265358979323846F / 360.0F; + constexpr static float ANG2RAD = 3.14159265358979323846F / 180.0F; + constexpr static float PI = 3.1415926535897932384626433832795F; + constexpr static float HALF_PI = 1.5707963267948966192313216916398F; static float cos(float x); static float asin(float x); static float mod(float x, float y); static inline float sin(float x) { return cos(x - HALF_PI); }; static inline float tan(float x) { return sin(x) / cos(x); } - static float sqrt(float x); static float invSqrt(float x); static inline u32 max(u32 a, u32 b) { return (a > b) ? a : b; } static inline s32 max(s32 a, s32 b) { return (a > b) ? a : b; } diff --git a/src/engine/loaders/dff_loader.cpp b/src/engine/loaders/dff_loader.cpp index abddbcd..23f73d7 100644 --- a/src/engine/loaders/dff_loader.cpp +++ b/src/engine/loaders/dff_loader.cpp @@ -244,6 +244,8 @@ void DffLoader::readGeometryExtension(MeshFrame *o_frame, char **materialNames, { u32 facesCount = readDwordFromArrayLE(t_buffer, t_ptrPos); u32 materialIndex = readDwordFromArrayLE(t_buffer, t_ptrPos); + o_frame->getMaterial(i).setSTsPresent(true); + o_frame->getMaterial(i).setNormalsPresent(true); o_frame->getMaterial(i).allocateFaces(facesCount); o_frame->getMaterial(i).setName(materialNames[materialIndex]); for (u32 j = 0; j < facesCount; j++) diff --git a/src/engine/loaders/md2_loader.cpp b/src/engine/loaders/md2_loader.cpp index d7a8924..d459c00 100644 --- a/src/engine/loaders/md2_loader.cpp +++ b/src/engine/loaders/md2_loader.cpp @@ -138,6 +138,8 @@ MeshFrame *MD2Loader::load(u32 &o_framesCount, char *t_subpath, char *t_nameWith { for (u32 x = 0; x < framesCount; x++) { + resultFrames[x].getMaterial(0).setSTsPresent(true); + resultFrames[x].getMaterial(0).setNormalsPresent(true); resultFrames[x].getMaterial(0).setVertexFace((i * 3) + j, triangle->index_xyz[j]); resultFrames[x].getMaterial(0).setSTFace((i * 3) + j, triangle->index_st[j]); resultFrames[x].getMaterial(0).setNormalFace((i * 3) + j, triangle->index_xyz[j]); diff --git a/src/engine/loaders/obj_loader.cpp b/src/engine/loaders/obj_loader.cpp index a200589..7c7662d 100644 --- a/src/engine/loaders/obj_loader.cpp +++ b/src/engine/loaders/obj_loader.cpp @@ -36,6 +36,8 @@ void ObjLoader::load(MeshFrame *o_result, char *t_filename, float t_scale, u8 t_ fseek(file, 0, SEEK_SET); u32 verticesI = 0, cordsI = 0, normalsI = 0, faceI = 0, vertexIndex[3], coordIndex[3], normalIndex[3]; s16 materialsI = -1; + Vector3 vector = Vector3(); + Point point = Point(); while (1) { char lineHeader[128]; // read the first word of the line @@ -44,13 +46,11 @@ void ObjLoader::load(MeshFrame *o_result, char *t_filename, float t_scale, u8 t_ { if (strcmp(lineHeader, "v") == 0) { - Vector3 vector = Vector3(); fscanf(file, "%f %f %f\n", &vector.x, &vector.y, &vector.z); o_result->setVertex(verticesI++, vector * t_scale); } else if (strcmp(lineHeader, "vt") == 0) { - Point point = Point(); fscanf(file, "%f %f\n", &point.x, &point.y); if (t_invertT) point.y = 1.0F - point.y; @@ -58,7 +58,6 @@ void ObjLoader::load(MeshFrame *o_result, char *t_filename, float t_scale, u8 t_ } else if (strcmp(lineHeader, "vn") == 0) { - Vector3 vector = Vector3(); fscanf(file, "%f %f %f\n", &vector.x, &vector.y, &vector.z); o_result->setNormal(normalsI++, vector); } @@ -71,32 +70,117 @@ void ObjLoader::load(MeshFrame *o_result, char *t_filename, float t_scale, u8 t_ } 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 + int *x = &res; // random assignment, to disable compilation warning + fpos_t start; + fgetpos(file, &start); + int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", x, x, x, x, x, x, x, x, x); + fsetpos(file, &start); + int newerMatches = 0; + + switch (matches) + { + /** Vs, VTs and VNs all set */ + case 9: + { + 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]); + } + break; + /** Loaded only two digits (V, VT) succesfuly. Not setting VN. */ + case 2: + { + fscanf(file, "%d/%d/ %d/%d/ %d/%d/\n", + &vertexIndex[0], &coordIndex[0], + &vertexIndex[1], &coordIndex[1], + &vertexIndex[2], &coordIndex[2]); + } + break; + /** Only V set. Checking for existance of VT or VN. */ + case 1: + { + /** Check for existance of V/// configuration.. */ + newerMatches = fscanf(file, "%d/// %d/// %d///\n", x, x, x); + fsetpos(file, &start); + if (newerMatches == 3) + { + /** Configuration confirmed. */ + fscanf(file, "%d/// %d/// %d///\n", &vertexIndex[0], &vertexIndex[1], &vertexIndex[2]); + } + else + { + /** Failed, checking configuration V//VN */ + newerMatches = fscanf(file, "%d//%d %d//%d %d//%d", x, x, x, x, x, x); + fsetpos(file, &start); + if (newerMatches == 6) + { + /** Configuration confirmed. */ + newerMatches = fscanf(file, "%d//%d %d//%d %d//%d", + &vertexIndex[0], &normalIndex[0], + &vertexIndex[1], &normalIndex[1], + &vertexIndex[2], &normalIndex[2]); + } + else + { + /**Unknown configuration.*/ + PRINT_ERR("Unknown .obj face for .obj file!"); + } + } + break; + } + default: + PRINT_ERR("Unknown faces format in .obj file!"); + break; + } + + if (matches == 9 || matches == 2 || matches == 1) { o_result->getMaterial(materialsI).setVertexFace(faceI, vertexIndex[0] - 1); o_result->getMaterial(materialsI).setVertexFace(faceI + 1, vertexIndex[1] - 1); o_result->getMaterial(materialsI).setVertexFace(faceI + 2, vertexIndex[2] - 1); - + } + if (matches == 9 || matches == 2) + { o_result->getMaterial(materialsI).setSTFace(faceI, coordIndex[0] - 1); o_result->getMaterial(materialsI).setSTFace(faceI + 1, coordIndex[1] - 1); o_result->getMaterial(materialsI).setSTFace(faceI + 2, coordIndex[2] - 1); + o_result->getMaterial(materialsI).setSTsPresent(true); + } + if (matches == 9) + { o_result->getMaterial(materialsI).setNormalFace(faceI, normalIndex[0] - 1); o_result->getMaterial(materialsI).setNormalFace(faceI + 1, normalIndex[1] - 1); o_result->getMaterial(materialsI).setNormalFace(faceI + 2, normalIndex[2] - 1); + o_result->getMaterial(materialsI).setNormalsPresent(true); faceI += 3; } + else if (matches == 2) + { + faceI += 2; + } + else if (matches == 1) + { + if (newerMatches == 3) + { + faceI += 1; + } + else if (newerMatches == 6) + { + o_result->getMaterial(materialsI).setNormalFace(faceI, normalIndex[0] - 1); + o_result->getMaterial(materialsI).setNormalFace(faceI + 1, normalIndex[1] - 1); + o_result->getMaterial(materialsI).setNormalFace(faceI + 2, normalIndex[2] - 1); + o_result->getMaterial(materialsI).setNormalsPresent(true); + faceI += 2; + } + } } } else break; } + o_result->calculateBoundingBoxes(); fclose(file); delete[] path; diff --git a/src/engine/loaders/png_loader.cpp b/src/engine/loaders/png_loader.cpp index bc46b9f..402800c 100644 --- a/src/engine/loaders/png_loader.cpp +++ b/src/engine/loaders/png_loader.cpp @@ -38,13 +38,11 @@ void PngLoader::load(Texture &o_texture, char *t_subfolder, char *t_name, char * char *path = String::createConcatenated(path_part2, t_extension); delete[] path_part1; delete[] path_part2; + FILE *file = fopen(path, "rb"); if (file == NULL) - { - PRINT_ERR("Failed to load .png file!"); - return; - } + PRINT_ERR("Failed to open .png file!"); png_structp png_ptr; png_infop info_ptr; @@ -56,29 +54,15 @@ void PngLoader::load(Texture &o_texture, char *t_subfolder, char *t_name, char * png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL); if (!png_ptr) - { - printf("PNG Read Struct Init Failed\n"); - fclose(file); - return; - } + PRINT_ERR("PNG struct info init failed(1)!"); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) - { - printf("PNG Info Struct Init Failed\n"); - fclose(file); - png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); - return; - } + PRINT_ERR("PNG struct info init failed(2)!"); if (setjmp(png_jmpbuf(png_ptr))) - { - printf("Got PNG Error!\n"); - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); - fclose(file); - return; - } + PRINT_ERR("PNG reader fatal error!"); png_init_io(png_ptr, file); @@ -114,80 +98,39 @@ void PngLoader::load(Texture &o_texture, char *t_subfolder, char *t_name, char * type = TEX_TYPE_RGB; break; default: - PRINT_ERR("This png format is not supported!"); + PRINT_ERR("This png format is not supported! RGB/RGBA only."); } o_texture.setSize(width, height, type); printf("PNGLoader - width: %d | height: %d\n", width, height); - if (type == TEX_TYPE_RGBA) - { - int row_bytes = png_get_rowbytes(png_ptr, info_ptr); - png_byte *row_pointers[height]; + size_t row_bytes = png_get_rowbytes(png_ptr, info_ptr); + png_byte *row_pointers[height]; + for (row = 0; row < height; row++) + row_pointers[row] = new png_byte[row_bytes]; - for (row = 0; row < height; row++) - row_pointers[row] = new png_byte[row_bytes]; + png_read_image(png_ptr, row_pointers); - png_read_image(png_ptr, row_pointers); + u32 x = 0; - struct pixel + for (i = 0; i < height; i++) + for (j = 0; j < width; j++) { - u8 r, g, b, a; - }; - - u32 x = 0; - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) + o_texture.setData(x, row_pointers[i][4 * j]); + o_texture.setData(x + 1, row_pointers[i][4 * j + 1]); + o_texture.setData(x + 2, row_pointers[i][4 * j + 2]); + if (type == TEX_TYPE_RGBA) { - o_texture.setData(x, row_pointers[i][4 * j]); - o_texture.setData(x + 1, row_pointers[i][4 * j + 1]); - o_texture.setData(x + 2, row_pointers[i][4 * j + 2]); o_texture.setData(x + 3, ((int)row_pointers[i][4 * j + 3] * 128 / 255)); x += 4; } - } - - for (row = 0; row < height; row++) - delete row_pointers[row]; - } - else if (type == TEX_TYPE_RGB) - { - int row_bytes = png_get_rowbytes(png_ptr, info_ptr); - png_byte *row_pointers[height]; - - for (row = 0; row < height; row++) - row_pointers[row] = new png_byte[row_bytes]; - - png_read_image(png_ptr, row_pointers); - - struct pixel3 - { - u8 r, g, b; - }; - - u32 x = 0; - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - o_texture.setData(x, row_pointers[i][4 * j]); - o_texture.setData(x + 1, row_pointers[i][4 * j + 1]); - o_texture.setData(x + 2, row_pointers[i][4 * j + 2]); + else if (type == TEX_TYPE_RGB) x += 3; - } } - for (row = 0; row < height; row++) - delete row_pointers[row]; - } - else - { - printf("This texture depth is not supported yet!\n"); - return; - } + for (row = 0; row < height; row++) + delete[] row_pointers[row]; - // Texture->Filter = GS_FILTER_NEAREST; png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); diff --git a/src/engine/models/bounding_box.cpp b/src/engine/models/bounding_box.cpp index dc90364..2b22fc9 100644 --- a/src/engine/models/bounding_box.cpp +++ b/src/engine/models/bounding_box.cpp @@ -46,4 +46,4 @@ BoundingBox::BoundingBox(Vector3 *t_vertices) BoundingBox::~BoundingBox() { -} \ No newline at end of file +} diff --git a/src/engine/models/math/matrix.cpp b/src/engine/models/math/matrix.cpp index ec927a1..c39ad20 100644 --- a/src/engine/models/math/matrix.cpp +++ b/src/engine/models/math/matrix.cpp @@ -17,11 +17,16 @@ // 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) +Matrix::Matrix() +{ + for (u8 i = 0; i < 16; i++) + data[i] = 0.0F; +} + +Matrix::Matrix(const float &m11, const float &m12, const float &m13, const float &m14, + const float &m21, const float &m22, const float &m23, const float &m24, + const float &m31, const float &m32, const float &m33, const float &m34, + const float &m41, const float &m42, const float &m43, const float &m44) { data[0] = m11; data[1] = m12; @@ -44,206 +49,51 @@ Matrix::Matrix(float m11, float m12, float m13, float m14, data[15] = m44; } -/** Create with another matrix values */ -Matrix::Matrix(const Matrix &v) +// ---- +// Operators +// ---- + +Vector3 Matrix::operator*(const Vector3 &v) const { - 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]; + float a[4] = {v.x, v.y, v.z, 1.0F}; + float res[4]; + asm volatile( + "lqc2 $vf4, 0x00(%1) \n\t" + "lqc2 $vf5, 0x10(%1) \n\t" + "lqc2 $vf6, 0x20(%1) \n\t" + "lqc2 $vf7, 0x30(%1) \n\t" + "lqc2 $vf8, 0x00(%2) \n\t" + "vmulax.xyzw $ACC, $vf4, $vf8 \n\t" + "vmadday.xyzw $ACC, $vf5, $vf8 \n\t" + "vmaddaz.xyzw $ACC, $vf6, $vf8 \n\t" + "vmaddw.xyzw $vf9, $vf7, $vf8 \n\t" + "sqc2 $vf9, 0x00(%0) \n\t" + : + : "r"(res), "r"(this->data), "r"(a)); + return Vector3(res[0], res[1], res[2]); } +// ---- +// Functions +// ---- + 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" + "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(const Vector3 &t_val) -{ - this->data[12] += t_val.x; // 3,0 - this->data[13] += t_val.y; // 3,1 - this->data[14] += t_val.z; // 3,2 -} - -void Matrix::rotateX(const float &t_radians) -{ - Matrix temp = Matrix(); - temp.identity(); - float c = Math::cos(t_radians); - float s = Math::sin(t_radians); - this->data[5] = c; // 1,1 - this->data[6] = s; // 1,2 - this->data[9] = -s; // 2,1 - this->data[10] = c; // 2,2 -} - -void Matrix::rotateY(const float &t_radians) -{ - Matrix temp = Matrix(); - temp.identity(); - float c = Math::cos(t_radians); - float s = Math::sin(t_radians); - this->data[0] = c; // 0,0 - this->data[2] = -s; // 0,3 - this->data[8] = s; // 2,0 - this->data[10] = c; // 2,2 -} - -void Matrix::rotateZ(const float &t_radians) -{ - Matrix temp = Matrix(); - temp.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*(const 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; -} - -void Matrix::operator*=(const Matrix &t) -{ - 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"(this->data), "r"(this->data), "r"(t.data) - : "memory"); -} - -/** 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) +void Matrix::setPerspective(const ScreenSettings &t_screen) { float fovYdiv2 = Math::HALF_ANG2RAD * t_screen.fov; float cotFOV = 1.0F / (Math::sin(fovYdiv2) / Math::cos(fovYdiv2)); @@ -275,42 +125,57 @@ void Matrix::setPerspective(ScreenSettings &t_screen) 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) +void Matrix::lookAt(const Vector3 &t_position, const Vector3 &t_target) { - Vector3 camForward, camUp, camRight; + VECTOR up_vec, view_vec; + VECTOR eye = {t_position.x, t_position.y, t_position.z, 1.0F}; + VECTOR obj = {t_target.x, t_target.y, t_target.z, 1.0F}; + asm volatile( + "lqc2 $vf4, 0x00(%2) # eye \n\t" + "lqc2 $vf5, 0x00(%3) # obj \n\t" + "vsub.xyz $vf7, $vf4, $vf5 # view_vec = $vf7 \n\t" + "vmove.xyzw $vf6, $vf0 \n\t" + "vaddw.y $vf6, $vf0, $vf0 # $vf6 = { 0.0f, 1.0f, 0.0f, 1.0f } \n\t" + "vopmula.xyz $ACC, $vf6, $vf7 \n\t" + "vopmsub.xyz $vf9, $vf7, $vf6 # vec = $vf9 \n\t" + "vopmula.xyz $ACC, $vf7, $vf9 \n\t" + "vopmsub.xyz $vf8, $vf9, $vf7 # up_vec = $vf8 \n\t" + "sqc2 $vf7, 0x00(%0) # view_vec \n\t" + "sqc2 $vf6, 0x00(%1) # up_vec \n\t" + : + : "r"(view_vec), "r"(up_vec), "r"(eye), "r"(obj)); + Matrix temp; + temp.setCamera(eye, view_vec, up_vec); + identity(); + cross(this->data, this->data, temp.data); - camForward = t_position - t_target; - camForward.normalize(); - camRight = t_up * camForward; - camRight.normalize(); - camUp = camForward * camRight; + // Vector3 camForward, camUp, camRight; + // Vector3 t_up = Vector3(0.0F, 1.0F, 0.0F); + // 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[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[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[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; + // data[3] = 0; + // data[7] = 0; + // data[11] = 0; + // data[15] = 1; } const void Matrix::print() const @@ -321,3 +186,186 @@ const void Matrix::print() const data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]); } + +// ---- +// Private +// ---- + +void Matrix::rotationX(const float &t_radians) +{ + float c = Math::cos(t_radians); + float s = Math::sin(t_radians); + this->data[5] = c; // 1,1 + this->data[6] = s; // 1,2 + this->data[9] = -s; // 2,1 + this->data[10] = c; // 2,2 +} + +void Matrix::rotationY(const float &t_radians) +{ + float c = Math::cos(t_radians); + float s = Math::sin(t_radians); + this->data[0] = c; // 0,0 + this->data[2] = -s; // 0,3 + this->data[8] = s; // 2,0 + this->data[10] = c; // 2,2 +} + +void Matrix::rotationZ(const float &t_radians) +{ + 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 +} + +void Matrix::rotationByAngle(const float &t_angle, const Vector3 &t_axis) +{ + Vector3 localAxis = Vector3(t_axis); + localAxis.normalize(); + float x = localAxis.x; + float y = localAxis.y; + float z = localAxis.z; + + float c = Math::cos(t_angle); + float s = Math::sin(t_angle); + + this->data[0] = x * x * (1 - c) + c; + this->data[1] = y * x * (1 - c) + z * s; + this->data[2] = x * z * (1 - c) - y * s; + this->data[3] = 0.0F; + + this->data[4] = x * y * (1 - c) - z * s; + this->data[5] = y * y * (1 - c) + c; + this->data[6] = y * z * (1 - c) + x * s; + this->data[7] = 0.0F; + + this->data[8] = x * z * (1 - c) + y * s; + this->data[9] = y * z * (1 - c) - x * s; + this->data[10] = z * z * (1 - c) + c; + this->data[11] = 0.0F; + + this->data[12] = 0.0F; + this->data[13] = 0.0F; + this->data[14] = 0.0F; + this->data[15] = 1.0F; +} + +void Matrix::translation(const Vector3 &t_val) +{ + this->data[12] = t_val.x; // 3,0 + this->data[13] = t_val.y; // 3,1 + this->data[14] = t_val.z; // 3,2 +} + +void Matrix::setScale(const Vector3 &t_val) +{ + this->data[0] = t_val.x; + this->data[5] = t_val.y; + this->data[10] = t_val.z; + this->data[15] = 1.0F; +} + +void Matrix::setCamera(const float t_pos[4], const float t_vz[4], const float t_vy[4]) +{ + // Matrix $vf4, $vf5, $vf6, $vf7 + // t_pos $vf8 + // t_vz $vf9 + // t_vy $vf10 + // vtmp $vf11 + asm volatile( + "lqc2 $vf9, 0x00(%2) \n\t" + "lqc2 $vf10, 0x00(%3) \n\t" + // mtmp.unit() + "vsub.w $vf5, $vf0, $vf0 # mtmp[1][PW] = 0.0F \n\t" + // vtmp.outerProduct(vy, vz); + "vopmula.xyz $ACC, $vf10, $vf9 \n\t" + "vopmsub.xyz $vf11, $vf9, $vf10 \n\t" + // mtmp[0] = vtmp.normalize(); + "vmul.xyz $vf12, $vf11, $vf11 \n\t" + "vaddy.x $vf12, $vf12, $vf12 \n\t" + "vaddz.x $vf12, $vf12, $vf12 \n\t" + "vrsqrt $Q, $vf0w, $vf12x \n\t" + "vsub.xyzw $vf4, $vf0, $vf0 \n\t" + "vwaitq \n\t" + "vmulq.xyz $vf4, $vf11, $Q \n\t" + // mtmp[2] = vz.normalize(); + "vmul.xyz $vf12, $vf9, $vf9 \n\t" + "vaddy.x $vf12, $vf12, $vf12 \n\t" + "vaddz.x $vf12, $vf12, $vf12 \n\t" + "vrsqrt $Q, $vf0w, $vf12x \n\t" + "vsub.xyzw $vf6, $vf0, $vf0 \n\t" + "vwaitq \n\t" + "vmulq.xyz $vf6, $vf9, $Q \n\t" + // mtmp[1].outerProduct(mtmp[2], mtmp[0]); + "vopmula.xyz $ACC, $vf6, $vf4 \n\t" + "vopmsub.xyz $vf5, $vf4, $vf6 \n\t" + // mtmp.transpose(pos); + "lqc2 $vf7, 0x00(%1) \n\t" + // m = mtmp.inverse(); + "qmfc2.ni $11, $vf0 \n\t" + "qmfc2.ni $8, $vf4 \n\t" + "qmfc2.ni $9, $vf5 \n\t" + "qmfc2.ni $10, $vf6 \n\t" + + "pextlw $12, $9, $8 \n\t" + "pextuw $13, $9, $8 \n\t" + "pextlw $14, $11, $10 \n\t" + "pextuw $15, $11, $10 \n\t" + "pcpyld $8, $14, $12 \n\t" + "pcpyud $9, $12, $14 \n\t" + "pcpyld $10, $15, $13 \n\t" + + "qmtc2.ni $8, $vf16 \n\t" + "qmtc2.ni $9, $vf17 \n\t" + "qmtc2.ni $10, $vf18 \n\t" + "vmulax.xyz $ACC, $vf16, $vf7 \n\t" + "vmadday.xyz $ACC, $vf17, $vf7 \n\t" + "vmaddz.xyz $vf5, $vf18, $vf7 \n\t" + "vsub.xyzw $vf5, $vf0, $vf5 \n\t" + + "sq $8, 0x00(%0) \n\t" + "sq $9, 0x10(%0) \n\t" + "sq $10, 0x20(%0) \n\t" + "sqc2 $vf5, 0x30(%0) \n\t" + : + : "r"(this->data), "r"(t_pos), "r"(t_vz), "r"(t_vy)); +} + +void Matrix::cross(float res[16], const float a[16], const float b[16]) const +{ + 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"(res), "r"(b), "r"(a) + : "memory"); +} diff --git a/src/engine/models/math/vector3.cpp b/src/engine/models/math/vector3.cpp index 7adafd3..6d71a91 100644 --- a/src/engine/models/math/vector3.cpp +++ b/src/engine/models/math/vector3.cpp @@ -9,108 +9,59 @@ */ #include "../../include/models/math/vector3.hpp" - #include "../../include/utils/math.hpp" -#include // ---- // Constructors/Destructors // ---- -/** Create by specifying 3 points */ -Vector3::Vector3(float t_x, float t_y, float t_z) -{ - x = t_x; - y = t_y; - z = t_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, const float &t_scale) -{ - 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)); - x *= t_scale; - y *= t_scale; - z *= t_scale; -} - -/** Create empty vector */ Vector3::Vector3() { - x = 0; - y = 0; - z = 0; + x = 0.0F; + y = 0.0F; + z = 0.0F; } -Vector3::~Vector3() {} - // ---- -// Methods +// Operators // ---- -Vector3 Vector3::operator+(Vector3 v) +Vector3 Vector3::operator+(const Vector3 &v) const { 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" + "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 Vector3::operator-(const Vector3 &v) const { 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" + "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 Vector3::operator*(const Vector3 &v) const { Vector3 res; - asm volatile( // VU0 Macro program - "lqc2 vf4, 0x0(%1) \n\t" // vf4 = this - "lqc2 vf5, 0x0(%2) \n\t" // vf5 = v - "vopmula.xyz ACC, vf4, vf5 \n\t" - "vopmsub.xyz vf8, vf5, vf4 \n\t" - "vsub.w vf8, vf00, vf00 \n\t" - "sqc2 vf8, 0x0(%0) \n\t" // vf8 = res + asm volatile( // VU0 Macro program + "lqc2 $vf4, 0x0(%1) \n\t" // $vf4 = this + "lqc2 $vf5, 0x0(%2) \n\t" // $vf5 = v + "vopmula.xyz $ACC, $vf4, $vf5 \n\t" + "vopmsub.xyz $vf8, $vf5, $vf4 \n\t" + "vsub.w $vf8, $vf0, $vf0 \n\t" + "sqc2 $vf8, 0x0(%0) \n\t" // $vf8 = res : : "r"(res.xyz), "r"(this->xyz), "r"(v.xyz)); // result.x = y * v.z - z * v.y; @@ -119,33 +70,21 @@ Vector3 Vector3::operator*(Vector3 &v) return res; } -Vector3 Vector3::operator*(const float &t) +Vector3 Vector3::operator*(const float &t) const { Vector3 result; asm volatile( - "lqc2 vf4, 0x0(%1) \n\t" + "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" + "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)); return result; } -void Vector3::operator*=(const float &t) -{ - asm volatile( - "lqc2 vf4, 0x0(%0) \n\t" - "mfc1 $8, %1 \n\t" - "qmtc2 $8, vf5 \n\t" - "vmulx.xyz vf4, vf4, vf5 \n\t" - "sqc2 vf4, 0x0(%0) \n\t" - : - : "r"(this->xyz), "f"(t)); -} - -Vector3 Vector3::operator/(float t) +Vector3 Vector3::operator/(const float &t) const { Vector3 result; result.x = x / t; @@ -154,54 +93,78 @@ Vector3 Vector3::operator/(float t) return result; } -u8 Vector3::shouldBeBackfaceCulled(const Vector3 *t_cameraPos, const Vector3 *v0, const Vector3 *v1, const Vector3 *v2) +void Vector3::operator+=(const Vector3 &t) { - 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)); - return dot <= 0.0F; -} - -/** Checks intersection with given square */ -u8 Vector3::collidesSquare(const Vector3 &t_min, const Vector3 &t_max) const -{ - 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(const Vector3 &t_min, const Vector3 &t_max) const -{ - 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" + "lqc2 $vf4, 0x0(%0) \n\t" + "lqc2 $vf5, 0x0(%1) \n\t" + "vadd.xyz $vf4, $vf4, $vf5 \n\t" + "sqc2 $vf4, 0x0(%0) \n\t" + : + : "r"(this->xyz), "r"(t.xyz)); +} + +void Vector3::operator*=(const float &t) +{ + asm volatile( + "lqc2 $vf4, 0x0(%0) \n\t" + "mfc1 $8, %1 \n\t" + "qmtc2 $8, $vf5 \n\t" + "vmulx.xyz $vf4, $vf4, $vf5 \n\t" + "sqc2 $vf4, 0x0(%0) \n\t" + : + : "r"(this->xyz), "f"(t)); +} + +// ---- +// Functions +// ---- + +void Vector3::set(const Vector3 &v) +{ + asm volatile( // VU0 Macro program + "lq $6, 0x0(%1) \n\t" + "sq $6, 0x0(%0) \n\t" + : + : "r"(this->xyz), "r"(v.xyz)); +} + +void Vector3::set(const float &t_x, const float &t_y, const float &t_z) +{ + x = t_x; + y = t_y; + z = t_z; +} + +float Vector3::innerProduct(const Vector3 &v) const +{ + 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)); + return result; + // return (x * v.x + y * v.y + z * v.z); +} + +float Vector3::length() const +{ + 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" "vwaitq \n\t" - "vaddq.x vf8, vf0, Q \n\t" - "qmfc2 $2, vf8 \n\t" + "vaddq.x $vf8, $vf0, $Q \n\t" + "qmfc2 $2, $vf8 \n\t" "mtc1 $2, %0 \n\t" : "=f"(result) : "r"(this->xyz)); @@ -212,114 +175,35 @@ float Vector3::length() 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" + "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" "vwaitq \n\t" - "vsub.xyz vf6, vf0, vf0 \n\t" - "vaddw.xyz vf6, vf6, vf4 \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" + "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)); - return result; - // return (x * v.x + y * v.y + z * v.z); -} - -void Vector3::set(const float &t_x, const float &t_y, const float &t_z) -{ - x = t_x; - y = t_y; - z = t_z; -} - -void Vector3::rotate(const Vector3 &v, u8 inversed) -{ - VECTOR cameraPos = {x, y, z, 0.0F}; - VECTOR rotation; - if (inversed) - { - rotation[0] = -v.x; - rotation[1] = -v.y; - rotation[2] = -v.z; - } - else - { - rotation[0] = v.x; - rotation[1] = v.y; - rotation[2] = v.z; - } - rotation[3] = 0.0F; - - MATRIX rotationMatrix; - matrix_unit(rotationMatrix); - matrix_rotate(rotationMatrix, rotationMatrix, rotation); - VECTOR result; - asm volatile( - "lqc2 vf4, 0x0(%1) \n\t" - "lqc2 vf5, 0x10(%1) \n\t" - "lqc2 vf6, 0x20(%1) \n\t" - "lqc2 vf7, 0x30(%1) \n\t" - "lqc2 vf8, 0x0(%2) \n\t" - "vmulax.xyzw ACC, vf4, vf8 \n\t" - "vmadday.xyzw ACC, vf5, vf8 \n\t" - "vmaddaz.xyzw ACC, vf6, vf8 \n\t" - "vmaddw.xyzw vf9, vf7, vf8 \n\t" - "sqc2 vf9, 0x0(%0) \n\t" - : - : "r"(&result), "r"(&rotationMatrix), "r"(&cameraPos)); - set(Vector3(result[0], result[1], result[2])); -} - -void Vector3::set(const 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)); -} - float Vector3::distanceTo(const Vector3 &v) const { 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" + "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" "vwaitq \n\t" - "vaddq.x vf8, vf0, Q \n\t" - "qmfc2 $2, vf8 \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)); @@ -329,7 +213,42 @@ float Vector3::distanceTo(const Vector3 &v) const // (this->z - v.z) * (this->z - v.z)); } -const void Vector3::print() const +u8 Vector3::shouldBeBackfaceCulled(const Vector3 *t_cameraPos, const Vector3 *t_v0, const Vector3 *t_v1, const Vector3 *t_v2) { - printf("Vector3(%f, %f, %f)\n", x, y, z); + 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"(t_v0->xyz), "r"(t_v1->xyz), "r"(t_v2->xyz)); + return dot <= 0.0F; +} + +void Vector3::setByLerp(const Vector3 &t_v1, const Vector3 &t_v2, const float &t_interp, const float &t_scale) +{ + 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"(&t_v1.xyz), "r"(&t_v2.xyz), "f"(t_interp)); + operator*=(t_scale); } diff --git a/src/engine/models/mesh.cpp b/src/engine/models/mesh.cpp index 5a47159..e4dd355 100644 --- a/src/engine/models/mesh.cpp +++ b/src/engine/models/mesh.cpp @@ -28,6 +28,7 @@ Mesh::Mesh() shouldBeFrustumCulled = true; shouldBeBackfaceCulled = false; shouldBeLighted = false; + _areFramesAllocated = false; _isMother = false; scale = 1.0F; framesCount = 0; @@ -40,13 +41,12 @@ Mesh::Mesh() animState.isStayFrameSet = false; animState.nextFrame = 0; animState.speed = 0.1F; - setDefaultColor(); setDefaultLODAndClut(); } Mesh::~Mesh() { - if (_isMother) + if (_areFramesAllocated) delete[] frames; } @@ -59,6 +59,7 @@ void Mesh::loadObj(char *t_subfolder, char *t_objFile, const float &t_scale, con ObjLoader loader = ObjLoader(); framesCount = 1; frames = new MeshFrame[framesCount]; + _areFramesAllocated = true; char *part1 = String::createConcatenated(t_subfolder, t_objFile); // "folder/object" char *finalPath = String::createConcatenated(part1, ".obj"); // "folder/object.obj" loader.load(&frames[0], finalPath, t_scale, t_invertT); @@ -78,6 +79,7 @@ void Mesh::loadObj(char *t_subfolder, char *t_objFile, const float &t_scale, con ObjLoader loader = ObjLoader(); framesCount = t_framesCount; frames = new MeshFrame[framesCount]; + _areFramesAllocated = true; char *part1 = String::createConcatenated(t_subfolder, t_objFile); // "folder/object" char *part2 = String::createConcatenated(part1, "_"); // "folder/object_" for (u32 i = 0; i < framesCount; i++) @@ -105,6 +107,7 @@ void Mesh::loadDff(char *t_subfolder, char *t_dffFile, const float &t_scale, con char *dffPath = String::createConcatenated(part1, ".dff"); framesCount = 1; frames = new MeshFrame[1]; + _areFramesAllocated = true; loader.load(frames, dffPath, t_scale, t_invertT); delete[] part1; delete[] dffPath; @@ -120,8 +123,11 @@ void Mesh::loadMD2(char *t_subfolder, char *t_md2File, const float &t_scale, con void Mesh::loadFrom(const Mesh &t_mesh) { - frames = t_mesh.frames; framesCount = t_mesh.framesCount; + frames = new MeshFrame[framesCount]; + _areFramesAllocated = true; + for (u32 i = 0; i < framesCount; i++) + frames[i].copyFrom(&t_mesh.getFrame(i)); } void Mesh::playAnimation(const u32 &t_startFrame, const u32 &t_endFrame) @@ -189,7 +195,7 @@ u32 Mesh::getDrawData(u32 t_materialIndex, VECTOR *o_vertices, VECTOR *o_normals asm volatile( // VU0 macro program: // Load vector with 1.0F values to VF21 - "lqc2 vf21, 0x0(%0) \n\t" // load "one vec" + "lqc2 $vf21, 0x0(%0) \n\t" // load "one vec" : : "r"(ONE_VEC)); @@ -215,34 +221,34 @@ u32 Mesh::getDrawData(u32 t_materialIndex, VECTOR *o_vertices, VECTOR *o_normals // Calculate lerp() and store data into calc3Vectors // Vertex 0 - "lqc2 vf4, 0x0(%3) \n\t" // vf4 = v1 - "lqc2 vf5, 0x0(%6) \n\t" // vf5 = v2 - "mfc1 $10, %9 \n\t" // vf6 = t - "qmtc2 $10, 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 + "lqc2 $vf4, 0x0(%3) \n\t" // $vf4 = v1 + "lqc2 $vf5, 0x0(%6) \n\t" // $vf5 = v2 + "mfc1 $10, %9 \n\t" // $vf6 = t + "qmtc2 $10, $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 // Vertex 1 - "lqc2 vf4, 0x0(%4) \n\t" // vf4 = v1 - "lqc2 vf5, 0x0(%7) \n\t" // vf5 = v2 - "mfc1 $10, %9 \n\t" // vf6 = t - "qmtc2 $10, 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(%1) \n\t" // v0 = vf9 + "lqc2 $vf4, 0x0(%4) \n\t" // $vf4 = v1 + "lqc2 $vf5, 0x0(%7) \n\t" // $vf5 = v2 + "mfc1 $10, %9 \n\t" // $vf6 = t + "qmtc2 $10, $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(%1) \n\t" // v0 = $vf9 // Vertex 2 - "lqc2 vf4, 0x0(%5) \n\t" // vf4 = v1 - "lqc2 vf5, 0x0(%8) \n\t" // vf5 = v2 - "mfc1 $10, %9 \n\t" // vf6 = t - "qmtc2 $10, 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(%2) \n\t" // v0 = vf9 + "lqc2 $vf4, 0x0(%5) \n\t" // $vf4 = v1 + "lqc2 $vf5, 0x0(%8) \n\t" // $vf5 = v2 + "mfc1 $10, %9 \n\t" // $vf6 = t + "qmtc2 $10, $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(%2) \n\t" // v0 = $vf9 : : "r"(calc3Vectors[0].xyz), @@ -262,12 +268,12 @@ u32 Mesh::getDrawData(u32 t_materialIndex, VECTOR *o_vertices, VECTOR *o_normals asm volatile( // VU0 macro program // Copy 0,1,2 vertices - "lqc2 vf1, 0x0(%3) \n\t" // load vert - "lqc2 vf2, 0x0(%4) \n\t" // load normal - "lqc2 vf3, 0x0(%5) \n\t" // load st - "sqc2 vf1, 0x0(%0) \n\t" // store vert - "sqc2 vf2, 0x0(%1) \n\t" // store normal - "sqc2 vf3, 0x0(%2) \n\t" // store st + "lqc2 $vf1, 0x0(%3) \n\t" // load vert + "lqc2 $vf2, 0x0(%4) \n\t" // load normal + "lqc2 $vf3, 0x0(%5) \n\t" // load st + "sqc2 $vf1, 0x0(%0) \n\t" // store vert + "sqc2 $vf2, 0x0(%1) \n\t" // store normal + "sqc2 $vf3, 0x0(%2) \n\t" // store st : : "r"(calc3Vectors[0].xyz), "r"(calc3Vectors[1].xyz), @@ -286,37 +292,37 @@ u32 Mesh::getDrawData(u32 t_materialIndex, VECTOR *o_vertices, VECTOR *o_normals // Copy data and set vert/normal "w" and st "z"+"w" to 1.0F // Vertex 0 - "lqc2 vf1, 0x0(%3) \n\t" // load vert - "lqc2 vf2, 0x0(%4) \n\t" // load normal - "lqc2 vf3, 0x0(%5) \n\t" // load st - "vadd.w vf1, vf20, vf21 \n\t" // set vert.w to 1.0F - "vadd.w vf2, vf20, vf21 \n\t" // set normal.W to 1.0F - "vadd.zw vf3, vf20, vf21 \n\t" // set st.zw to 1.0F - "sqc2 vf1, 0x0(%0) \n\t" // store vert - "sqc2 vf2, 0x0(%1) \n\t" // store normal - "sqc2 vf3, 0x0(%2) \n\t" // store st + "lqc2 $vf1, 0x0(%3) \n\t" // load vert + "lqc2 $vf2, 0x0(%4) \n\t" // load normal + "lqc2 $vf3, 0x0(%5) \n\t" // load st + "vadd.w $vf1, $vf20, $vf21 \n\t" // set vert.w to 1.0F + "vadd.w $vf2, $vf20, $vf21 \n\t" // set normal.W to 1.0F + "vadd.zw $vf3, $vf20, $vf21 \n\t" // set st.zw to 1.0F + "sqc2 $vf1, 0x0(%0) \n\t" // store vert + "sqc2 $vf2, 0x0(%1) \n\t" // store normal + "sqc2 $vf3, 0x0(%2) \n\t" // store st // Vertex 1 - "lqc2 vf1, 0x0(%9) \n\t" // load vert - "lqc2 vf2, 0x0(%10) \n\t" // load normal - "lqc2 vf3, 0x0(%11) \n\t" // load st - "vadd.w vf1, vf20, vf21 \n\t" // set vert.w to 1.0F - "vadd.w vf2, vf20, vf21 \n\t" // set normal.W to 1.0F - "vadd.zw vf3, vf20, vf21 \n\t" // set st.zw to 1.0F - "sqc2 vf1, 0x0(%6) \n\t" // store vert - "sqc2 vf2, 0x0(%7) \n\t" // store normal - "sqc2 vf3, 0x0(%8) \n\t" // store st + "lqc2 $vf1, 0x0(%9) \n\t" // load vert + "lqc2 $vf2, 0x0(%10) \n\t" // load normal + "lqc2 $vf3, 0x0(%11) \n\t" // load st + "vadd.w $vf1, $vf20, $vf21 \n\t" // set vert.w to 1.0F + "vadd.w $vf2, $vf20, $vf21 \n\t" // set normal.W to 1.0F + "vadd.zw $vf3, $vf20, $vf21 \n\t" // set st.zw to 1.0F + "sqc2 $vf1, 0x0(%6) \n\t" // store vert + "sqc2 $vf2, 0x0(%7) \n\t" // store normal + "sqc2 $vf3, 0x0(%8) \n\t" // store st // Vertex 2 - "lqc2 vf1, 0x0(%15) \n\t" // load vert - "lqc2 vf2, 0x0(%16) \n\t" // load normal - "lqc2 vf3, 0x0(%17) \n\t" // load st - "vadd.w vf1, vf20, vf21 \n\t" // set vert.w to 1.0F - "vadd.w vf2, vf20, vf21 \n\t" // set normal.W to 1.0F - "vadd.zw vf3, vf20, vf21 \n\t" // set st.zw to 1.0F - "sqc2 vf1, 0x0(%12) \n\t" // store vert - "sqc2 vf2, 0x0(%13) \n\t" // store normal - "sqc2 vf3, 0x0(%14) \n\t" // store st + "lqc2 $vf1, 0x0(%15) \n\t" // load vert + "lqc2 $vf2, 0x0(%16) \n\t" // load normal + "lqc2 $vf3, 0x0(%17) \n\t" // load st + "vadd.w $vf1, $vf20, $vf21 \n\t" // set vert.w to 1.0F + "vadd.w $vf2, $vf20, $vf21 \n\t" // set normal.W to 1.0F + "vadd.zw $vf3, $vf20, $vf21 \n\t" // set st.zw to 1.0F + "sqc2 $vf1, 0x0(%12) \n\t" // store vert + "sqc2 $vf2, 0x0(%13) \n\t" // store normal + "sqc2 $vf3, 0x0(%14) \n\t" // store st : : "r"(o_vertices[addedFaces]), @@ -375,16 +381,6 @@ u8 Mesh::isInFrustum(Plane *t_frustumPlanes) return boxResult; } -/** 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; -} - /** Sets texture level of details settings and CLUT settings */ void Mesh::setDefaultLODAndClut() { diff --git a/src/engine/models/mesh_frame.cpp b/src/engine/models/mesh_frame.cpp index 0e224cd..4fc959f 100644 --- a/src/engine/models/mesh_frame.cpp +++ b/src/engine/models/mesh_frame.cpp @@ -8,6 +8,7 @@ # Sandro Sobczyński */ +#include #include "../include/models/mesh_frame.hpp" #include "../include/utils/debug.hpp" @@ -17,6 +18,7 @@ MeshFrame::MeshFrame() { + id = rand() % 1000000; vertexCount = 0; stsCount = 0; normalsCount = 0; @@ -25,19 +27,23 @@ MeshFrame::MeshFrame() _areVerticesAllocated = false; _areNormalsAllocated = false; _areMaterialsAllocated = false; + _isMother = true; } MeshFrame::~MeshFrame() { - if (_areSTsAllocated) - delete[] sts; - if (_areVerticesAllocated) - delete[] vertices; - if (_areNormalsAllocated) - delete[] normals; + if (_isMother) + { + if (_areSTsAllocated) + delete[] sts; + if (_areVerticesAllocated) + delete[] vertices; + if (_areNormalsAllocated) + delete[] normals; + delete boundingBoxObj; + } if (_areMaterialsAllocated) delete[] materials; - delete boundingBoxObj; } // ---- @@ -94,14 +100,12 @@ void MeshFrame::allocateMaterials(const u32 &t_val) void MeshFrame::calculateBoundingBoxes() { - Vector3 boundingBox[8]; if (!_areVerticesAllocated) - { PRINT_ERR("Can't calculate bounding box, because vertices were not allocated!"); - return; - } + for (u32 i = 0; i < materialsCount; i++) materials->calculateBoundingBox(vertices, vertexCount); + float lowX, lowY, lowZ, hiX, hiY, hiZ; lowX = hiX = vertices[0].x; lowY = hiY = vertices[0].y; @@ -124,6 +128,7 @@ void MeshFrame::calculateBoundingBoxes() hiZ = vertices[i].z; } + Vector3 boundingBox[8]; boundingBox[0].set(lowX, lowY, lowZ); boundingBox[1].set(lowX, lowY, hiZ); boundingBox[2].set(lowX, hiY, lowZ); @@ -135,7 +140,30 @@ void MeshFrame::calculateBoundingBoxes() boundingBox[7].set(hiX, hiY, hiZ); _isBoundingBoxCalculated = true; - //BoundingBox is declared on the heap to prevent any ill-formed default - //constructor instantiated BoundingBox objects. + // BoundingBox is declared on the heap to prevent any ill-formed default + // constructor instantiated BoundingBox objects. boundingBoxObj = new BoundingBox(boundingBox); } + +void MeshFrame::copyFrom(MeshFrame *t_refCopy) +{ + vertexCount = t_refCopy->vertexCount; + stsCount = t_refCopy->stsCount; + normalsCount = t_refCopy->normalsCount; + materialsCount = t_refCopy->materialsCount; + materials = new MeshMaterial[materialsCount]; + for (u32 i = 0; i < materialsCount; i++) + materials[i].copyFrom(&t_refCopy->materials[i]); + _areSTsAllocated = true; + _areVerticesAllocated = true; + _areNormalsAllocated = true; + _areMaterialsAllocated = true; + vertices = t_refCopy->vertices; + sts = t_refCopy->sts; + normals = t_refCopy->normals; + + boundingBoxObj = t_refCopy->boundingBoxObj; + _isBoundingBoxCalculated = true; + + _isMother = false; +} diff --git a/src/engine/models/mesh_material.cpp b/src/engine/models/mesh_material.cpp index d6108da..b758840 100644 --- a/src/engine/models/mesh_material.cpp +++ b/src/engine/models/mesh_material.cpp @@ -25,18 +25,25 @@ MeshMaterial::MeshMaterial() _isNameSet = false; _areFacesAllocated = false; _isBoundingBoxCalculated = false; + _areSTsPresent = false; + _areNormalsPresent = false; + _isMother = true; + setDefaultColor(); } MeshMaterial::~MeshMaterial() { - if (_areFacesAllocated) + if (_isMother) { - delete[] vertexFaces; - delete[] stFaces; - delete[] normalFaces; + if (_areFacesAllocated) + { + delete[] vertexFaces; + delete[] stFaces; + delete[] normalFaces; + } + if (_isNameSet) + delete[] name; } - if (_isNameSet) - delete[] name; } // ---- @@ -102,7 +109,6 @@ u8 MeshMaterial::isInFrustum(Plane *t_frustumPlanes, const Vector3 &position) void MeshMaterial::calculateBoundingBox(Vector3 *t_vertices, u32 t_vertCount) { - Vector3 boundingBox[8]; float lowX, lowY, lowZ, hiX, hiY, hiZ; lowX = hiX = t_vertices[vertexFaces[0]].x; lowY = hiY = t_vertices[vertexFaces[0]].y; @@ -124,6 +130,8 @@ void MeshMaterial::calculateBoundingBox(Vector3 *t_vertices, u32 t_vertCount) if (hiZ < t_vertices[vertexFaces[i]].z) hiZ = t_vertices[vertexFaces[i]].z; } + + Vector3 boundingBox[8]; boundingBox[0].set(lowX, lowY, lowZ); boundingBox[1].set(lowX, lowY, hiZ); boundingBox[2].set(lowX, hiY, lowZ); @@ -139,3 +147,32 @@ void MeshMaterial::calculateBoundingBox(Vector3 *t_vertices, u32 t_vertCount) //constructor instantiated BoundingBox objects. boundingBoxObj = new BoundingBox(boundingBox); } + +void MeshMaterial::copyFrom(MeshMaterial *t_refCopy) +{ + _isNameSet = true; + name = t_refCopy->name; + + _isBoundingBoxCalculated = true; + boundingBoxObj = t_refCopy->boundingBoxObj; + + vertexFaces = t_refCopy->vertexFaces; + stFaces = t_refCopy->stFaces; + normalFaces = t_refCopy->normalFaces; + facesCount = t_refCopy->facesCount; + _areSTsPresent = t_refCopy->_areSTsPresent; + _areNormalsPresent = t_refCopy->_areNormalsPresent; + _areFacesAllocated = true; + + _isMother = false; +} + +/** Set's default object color + no transparency */ +void MeshMaterial::setDefaultColor() +{ + color.r = 0x80; + color.g = 0x80; + color.b = 0x80; + color.a = 0x80; + color.q = 1.0F; +} diff --git a/src/engine/models/texture.cpp b/src/engine/models/texture.cpp index 8bfb78d..1c247b3 100644 --- a/src/engine/models/texture.cpp +++ b/src/engine/models/texture.cpp @@ -82,18 +82,9 @@ void Texture::setWrapSettings(const WrapSettings t_horizontal, const WrapSetting wrapSettings.vertical = t_vertical; } -void Texture::addLink(const u32 &t_meshId, const u32 &t_materialId) +void Texture::addLink(const u32 &t_id) { TextureLink link; - link.materialId = t_materialId; - link.meshOrSpriteId = t_meshId; - texLinks.push_back(link); -} - -void Texture::addLink(const u32 &t_spriteId) -{ - TextureLink link; - link.materialId = 0; - link.meshOrSpriteId = t_spriteId; + link.id = t_id; texLinks.push_back(link); } diff --git a/src/engine/modules/audio.cpp b/src/engine/modules/audio.cpp index 2d7e836..f7b51c0 100644 --- a/src/engine/modules/audio.cpp +++ b/src/engine/modules/audio.cpp @@ -89,24 +89,25 @@ void Audio::setSongVolume(const u8 &t_vol) u32 Audio::addSongListener(AudioListener *t_listener) { - AudioListenerRef ref; - ref.id = rand() % 1000000; - ref.listener = t_listener; + AudioListenerRef *ref = new AudioListenerRef; + ref->id = rand() % 1000000; + ref->listener = t_listener; songListeners.push_back(ref); - return ref.id; + return ref->id; } void Audio::removeSongListener(const u32 &t_id) { s32 index = -1; for (u32 i = 0; i < songListeners.size(); i++) - if (songListeners[i].id == t_id) + if (songListeners[i]->id == t_id) { index = i; break; } if (index == -1) PRINT_ERR("Cant remove listener because given id was not found!"); + delete songListeners[index]; songListeners.erase(songListeners.begin() + index); } @@ -160,7 +161,7 @@ void Audio::playADPCM(audsrv_adpcm_t *t_adpcm, const s8 &t_ch) void Audio::startThread(FileService *t_fileService) { PRINT_LOG("Creating audio thread"); - fileService = t_fileService; + // fileService = t_fileService; extern void *_gp; thread.func = (void *)Audio::mainThread; thread.stack = threadStack; @@ -177,6 +178,20 @@ void Audio::startThread(FileService *t_fileService) /** Main thread loop */ void Audio::threadLoop() { + // --- + // TODO - bug here, GCC11 is doing some optimizations and this method probably think that + // "songPlaying" is false + on real PS2 I see that program tries to turn on this + // method as rarely as possible (slow, flickering sound). On GCC 3.2.3 this one was fine lol!. + if (songPlaying) // HACK1 - im not proud of that + songPlaying = 1; + if (songLoaded) + songLoaded = 1; + if (hack == 1) // HACK2 - lets give some work to gcc lol + hack = 2; + else + hack = 1; + // --- + if (!songPlaying || !songLoaded) return; if (songFinished) @@ -186,7 +201,7 @@ void Audio::threadLoop() { printf("Running again.\n"); for (u32 i = 0; i < getSongListenersCount(); i++) - songListeners[i].listener->onAudioFinish(); + songListeners[i]->listener->onAudioFinish(); rewindSongToStart(); } else @@ -202,7 +217,7 @@ void Audio::threadLoop() WaitSema(fillbufferSema); // wait until previous chunk wasn't finished audsrv_play_audio(wavChunk, chunkReadStatus); for (u32 i = 0; i < getSongListenersCount(); i++) - songListeners[i].listener->onAudioTick(); + songListeners[i]->listener->onAudioTick(); } chunkReadStatus = fread(wavChunk, 1, sizeof(wavChunk), wav); diff --git a/src/engine/modules/camera_base.cpp b/src/engine/modules/camera_base.cpp index 124ee77..8453012 100644 --- a/src/engine/modules/camera_base.cpp +++ b/src/engine/modules/camera_base.cpp @@ -18,7 +18,7 @@ // Constructors/Destructors // ---- -CameraBase::CameraBase(ScreenSettings *t_screen, Vector3 *t_position, Vector3 *t_up) +CameraBase::CameraBase(ScreenSettings *t_screen, Vector3 *t_position) : screen(t_screen) { PRINT_LOG("Initializing frustum"); @@ -30,7 +30,7 @@ CameraBase::CameraBase(ScreenSettings *t_screen, Vector3 *t_position, Vector3 *t farHeight = tang * farPlaneDist; farWidth = farHeight * screen->aspectRatio; p_position = t_position; - p_up = t_up; + up.set(0.0F, 1.0F, 0.0F); PRINT_LOG("CameraBase initialized!"); } @@ -41,7 +41,7 @@ CameraBase::CameraBase(ScreenSettings *t_screen, Vector3 *t_position, Vector3 *t void CameraBase::lookAt(Vector3 &t_target) { updatePlanes(t_target); - worldView.lookAt(*p_up, *p_position, t_target); + view.lookAt(*p_position, t_target); } void CameraBase::updatePlanes(Vector3 t_target) @@ -51,7 +51,7 @@ void CameraBase::updatePlanes(Vector3 t_target) Z = *p_position - t_target; Z.normalize(); // X axis of camera of given "up" vector and Z axis - X = *p_up * Z; + X = up * Z; X.normalize(); // the real "up" vector is the cross product of Z and X Y = Z * X; diff --git a/src/engine/modules/gif_sender.cpp b/src/engine/modules/gif_sender.cpp index 08dad58..cf0eac5 100644 --- a/src/engine/modules/gif_sender.cpp +++ b/src/engine/modules/gif_sender.cpp @@ -130,22 +130,17 @@ void GifSender::addClear(zbuffer_t *t_zBuffer, color_t *t_rgb) packet2_chain_close_tag(currentPacket); } -/** 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::addObject(RenderData *t_renderData, Mesh &t_mesh, u32 vertexCount, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, LightBulb *t_bulbs, u16 t_bulbsCount, texbuffer_t *textureBuffer) +/** Adds meshes to current packet */ +void GifSender::addObject(RenderData *t_renderData, Mesh &t_mesh, u32 vertexCount, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, LightBulb *t_bulbs, u16 t_bulbsCount, texbuffer_t *textureBuffer, color_t *t_color) { packet2_chain_open_cnt(currentPacket, 0, 0, 0); packet2_update(currentPacket, draw_texture_sampling(currentPacket->next, 0, &t_mesh.lod)); packet2_update(currentPacket, draw_texturebuffer(currentPacket->next, 0, textureBuffer, &t_mesh.clut)); - packet2_update(currentPacket, draw_prim_start(currentPacket->next, 0, t_renderData->prim, &t_mesh.color)); + packet2_update(currentPacket, draw_prim_start(currentPacket->next, 0, t_renderData->prim, t_color)); xyz = new xyz_t[vertexCount]; rgbaq = new color_t[vertexCount]; st = new texel_t[vertexCount]; - calc3DObject(*t_renderData->perspective, t_mesh, vertexCount, vertices, normals, coordinates, t_renderData, t_bulbs, t_bulbsCount); + calc3DObject(*t_renderData->projection, t_mesh, vertexCount, vertices, normals, coordinates, t_renderData, t_bulbs, t_bulbsCount, t_color); addCurrentCalcs(vertexCount); delete[] xyz; delete[] rgbaq; @@ -155,12 +150,9 @@ void GifSender::addObject(RenderData *t_renderData, Mesh &t_mesh, u32 vertexCoun } /** 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 + * After it addCurrentCalcs() can be done */ -void GifSender::calc3DObject(Matrix t_perspective, Mesh &t_mesh, u32 vertexCount, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, RenderData *t_renderData, LightBulb *t_bulbs, u16 t_bulbsCount) +void GifSender::calc3DObject(Matrix t_perspective, Mesh &t_mesh, u32 vertexCount, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, RenderData *t_renderData, LightBulb *t_bulbs, u16 t_bulbsCount, color_t *t_color) { VECTOR *colors = new VECTOR[vertexCount]; VECTOR position, rotation; @@ -176,7 +168,7 @@ void GifSender::calc3DObject(Matrix t_perspective, Mesh &t_mesh, u32 vertexCount create_local_light(localLight, rotation); // I cant put perspective from renderData here. ee-gcc bug? - create_local_screen(localScreen, localWorld, t_renderData->worldView->data, t_perspective.data); + create_local_screen(localScreen, localWorld, t_renderData->view->data, t_perspective.data); if (SHOULD_BE_LIGHTED) { @@ -195,9 +187,9 @@ void GifSender::calc3DObject(Matrix t_perspective, Mesh &t_mesh, u32 vertexCount for (u32 i = 0; i < vertexCount; i++) { // Apply the light value to the colour. - colors[i][0] = (t_mesh.color.r * lights[i][0]); - colors[i][1] = (t_mesh.color.g * lights[i][1]); - colors[i][2] = (t_mesh.color.b * lights[i][2]); + colors[i][0] = (t_color->r * lights[i][0]); + colors[i][1] = (t_color->g * lights[i][1]); + colors[i][2] = (t_color->b * lights[i][2]); vector_clamp(colors[i], colors[i], 0.00F, 1.99F); } @@ -209,14 +201,14 @@ void GifSender::calc3DObject(Matrix t_perspective, Mesh &t_mesh, u32 vertexCount else for (u32 i = 0; i < vertexCount; i++) { - colors[i][0] = t_mesh.color.r / 128.0F; - colors[i][1] = t_mesh.color.g / 128.0F; - colors[i][2] = t_mesh.color.b / 128.0F; + colors[i][0] = t_color->r / 128.0F; + colors[i][1] = t_color->g / 128.0F; + colors[i][2] = t_color->b / 128.0F; } calculate_vertices(vertices, vertexCount, vertices, localScreen); - convertCalcs(vertexCount, vertices, colors, coordinates, t_mesh.color); + convertCalcs(vertexCount, vertices, colors, coordinates, *t_color); delete[] colors; } diff --git a/src/engine/modules/renderer.cpp b/src/engine/modules/renderer.cpp index 02cadff..f554b82 100644 --- a/src/engine/modules/renderer.cpp +++ b/src/engine/modules/renderer.cpp @@ -13,8 +13,6 @@ #include #include #include -#include -#include #include "../include/utils/debug.hpp" #include "../include/utils/math.hpp" @@ -22,6 +20,9 @@ // Constructors/Destructors // ---- +static const float GS_CENTER = 4096.0F; +static const float SCREEN_CENTER = GS_CENTER / 2.0F; + /** Initialize DMA<->GIF channel * Allocate buffers * Initialize screen @@ -35,23 +36,23 @@ 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); + screen = t_screen; context = 0; isTextureVRAMAllocated = false; isVSyncEnabled = true; isFrameEmpty = false; lastTextureId = 0; flipPacket = packet2_create(4, P2_TYPE_UNCACHED_ACCL, P2_MODE_NORMAL, 0); - allocateBuffers(t_screen->width, t_screen->height); - initDrawingEnv(t_screen->width, t_screen->height); + allocateBuffers((int)t_screen->width, (int)t_screen->height); + initDrawingEnv(); setPrim(); worldColor.r = 0x10; worldColor.g = 0x10; worldColor.b = 0x10; - screen = t_screen; gifSender = new GifSender(t_packetSize, t_screen, &light); vifSender = new VifSender(&light); perspective.setPerspective(*t_screen); - renderData.perspective = &perspective; + renderData.projection = &perspective; PRINT_LOG("Renderer initialized!"); } @@ -104,7 +105,7 @@ void Renderer::changeTexture(Texture *t_tex) void Renderer::draw(Sprite &t_sprite) { - Texture *texture = textureRepo.getBySprite(t_sprite.getId()); + Texture *texture = textureRepo.getBySpriteOrMesh(t_sprite.getId()); texrect_t rect; float sizeX, sizeY; if (t_sprite.getMode() == MODE_REPEAT) @@ -142,7 +143,7 @@ void Renderer::draw(Sprite &t_sprite) beginFrameIfNeeded(); changeTexture(texture); packet2_t *packet2 = packet2_create(12, P2_TYPE_NORMAL, P2_MODE_NORMAL, 0); - packet2_update(packet2, draw_primitive_xyoffset(packet2->next, 0, 2048, 2048)); + packet2_update(packet2, draw_primitive_xyoffset(packet2->next, 0, SCREEN_CENTER, SCREEN_CENTER)); packet2_utils_gif_add_set(packet2, 1); packet2_utils_gs_add_texbuff_clut(packet2, &textureBuffer, &t_sprite.clut); draw_enable_blending(); @@ -151,7 +152,8 @@ void Renderer::draw(Sprite &t_sprite) draw_primitive_xyoffset( packet2->next, 0, - (2048 - (screen->width / 2)), (2048 - (screen->height / 2)))); + SCREEN_CENTER - (screen->width / 2.0F), + SCREEN_CENTER - (screen->height / 2.0F))); draw_disable_blending(); packet2_update(packet2, draw_finish(packet2->next)); dma_channel_wait(DMA_CHANNEL_GIF, 0); @@ -160,14 +162,14 @@ void Renderer::draw(Sprite &t_sprite) } /** Initializes drawing environment (1st app packet) */ -void Renderer::initDrawingEnv(float t_screenW, float t_screenH) +void Renderer::initDrawingEnv() { PRINT_LOG("Initializing drawing environment"); - u16 halfW = (u16)t_screenW / 2; - u16 halfH = (u16)t_screenH / 2; packet2_t *packet2 = packet2_create(20, P2_TYPE_NORMAL, P2_MODE_NORMAL, 0); packet2_update(packet2, draw_setup_environment(packet2->base, 0, frameBuffers, &(zBuffer))); - packet2_update(packet2, draw_primitive_xyoffset(packet2->next, 0, (2048 - halfW), (2048 - halfH))); + packet2_update(packet2, draw_primitive_xyoffset(packet2->next, 0, + SCREEN_CENTER - (screen->width / 2.0F), + SCREEN_CENTER - (screen->height / 2.0F))); packet2_update(packet2, draw_finish(packet2->next)); dma_channel_send_packet2(packet2, DMA_CHANNEL_GIF, true); dma_channel_wait(DMA_CHANNEL_GIF, 0); @@ -198,106 +200,141 @@ void Renderer::setWorldColor(const color_t &t_rgb) } /** Defines and allocates framebuffers and zbuffer */ -void Renderer::allocateBuffers(float t_screenW, float t_screenH) +void Renderer::allocateBuffers(int t_screenW, int t_screenH) { - frameBuffers[0].width = (u16)t_screenW; - frameBuffers[0].height = (u16)t_screenH; + frameBuffers[0].width = (unsigned int)t_screenW; + frameBuffers[0].height = (unsigned int)t_screenH; frameBuffers[0].mask = 0; - frameBuffers[0].psm = GS_PSM_24; - frameBuffers[0].address = graph_vram_allocate((u16)t_screenW, (u16)t_screenH, frameBuffers[0].psm, GRAPH_ALIGN_PAGE); + frameBuffers[0].psm = GS_PSM_32; + frameBuffers[0].address = graph_vram_allocate(t_screenW, t_screenH, frameBuffers[0].psm, GRAPH_ALIGN_PAGE); - frameBuffers[1].width = (u16)t_screenW; - frameBuffers[1].height = (u16)t_screenH; + frameBuffers[1].width = (unsigned int)t_screenW; + frameBuffers[1].height = (unsigned int)t_screenH; frameBuffers[1].mask = 0; - frameBuffers[1].psm = GS_PSM_24; - frameBuffers[1].address = graph_vram_allocate((u16)t_screenW, (u16)t_screenH, frameBuffers[1].psm, GRAPH_ALIGN_PAGE); + frameBuffers[1].psm = GS_PSM_32; + frameBuffers[1].address = graph_vram_allocate(t_screenW, 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_24; - zBuffer.address = graph_vram_allocate((u16)t_screenW, (u16)t_screenH, zBuffer.zsm, GRAPH_ALIGN_PAGE); + zBuffer.address = graph_vram_allocate(t_screenW, 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); + graph_initialize(frameBuffers[0].address, frameBuffers[0].width, frameBuffers[0].height, frameBuffers[0].psm, 0, 0); } /// --- Draw: PATH3 -void Renderer::drawByPath3(Mesh *t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount) -{ - for (u16 i = 0; i < t_amount; i++) - drawByPath3(t_meshes[i], t_bulbs, t_bulbsCount); -} +// Obsolete +// void Renderer::drawByPath3(Mesh *t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount) +// { +// for (u16 i = 0; i < t_amount; i++) +// drawByPath3(t_meshes[i], t_bulbs, t_bulbsCount); +// } -void Renderer::drawByPath3(Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount) -{ - beginFrameIfNeeded(); - if (!t_mesh.isDataLoaded()) - PRINT_ERR("Can't draw, because no mesh data was loaded!"); - if (t_mesh.getCurrentAnimationFrame() != t_mesh.getNextAnimationFrame()) - t_mesh.animate(); - for (u32 i = 0; i < t_mesh.getMaterialsCount(); i++) - { - if (t_mesh.shouldBeFrustumCulled && !t_mesh.getMaterial(i).isInFrustum(renderData.frustumPlanes, t_mesh.position)) - return; - Texture *tex = textureRepo.getByMesh(t_mesh.getId(), t_mesh.getMaterial(i).getId()); - changeTexture(tex); - gifSender->initPacket(context); - u32 vertCount = t_mesh.getMaterial(i).getFacesCount(); - VECTOR *vertices = new VECTOR[vertCount]; - VECTOR *normals = new VECTOR[vertCount]; - VECTOR *coordinates = new VECTOR[vertCount]; - vertCount = t_mesh.getDrawData(i, vertices, normals, coordinates, *renderData.cameraPosition); - gifSender->addObject(&renderData, t_mesh, vertCount, vertices, normals, coordinates, t_bulbs, t_bulbsCount, &textureBuffer); - gifSender->sendPacket(); - delete[] vertices; - delete[] normals; - delete[] coordinates; - } -} +// Obsolete +// void Renderer::drawByPath3(Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount) +// { +// beginFrameIfNeeded(); +// if (!t_mesh.isDataLoaded()) +// PRINT_ERR("Can't draw, because no mesh data was loaded!"); +// if (t_mesh.getCurrentAnimationFrame() != t_mesh.getNextAnimationFrame()) +// t_mesh.animate(); +// for (u32 i = 0; i < t_mesh.getMaterialsCount(); i++) +// { +// MeshMaterial *material = &t_mesh.getMaterial(i); +// if (t_mesh.shouldBeFrustumCulled && !material->isInFrustum(renderData.frustumPlanes, t_mesh.position)) +// return; +// Texture *tex = textureRepo.getBySpriteOrMesh(material->getId()); +// changeTexture(tex); +// gifSender->initPacket(context); +// u32 vertCount = material->getFacesCount(); +// VECTOR *vertices = new VECTOR[vertCount]; +// VECTOR *normals = new VECTOR[vertCount]; +// VECTOR *coordinates = new VECTOR[vertCount]; +// vertCount = t_mesh.getDrawData(i, vertices, normals, coordinates, *renderData.cameraPosition); +// gifSender->addObject(&renderData, t_mesh, vertCount, vertices, normals, coordinates, t_bulbs, t_bulbsCount, &textureBuffer, &material->color); +// gifSender->sendPacket(); +// delete[] vertices; +// delete[] normals; +// delete[] coordinates; +// } +// } -void Renderer::drawByPath3(Mesh *t_meshes, u16 t_amount) { drawByPath3(t_meshes, t_amount, NULL, 0); } +// Obsolete +// void Renderer::drawByPath3(Mesh *t_meshes, u16 t_amount) { drawByPath3(t_meshes, t_amount, NULL, 0); } -void Renderer::drawByPath3(Mesh &t_mesh) { drawByPath3(t_mesh, NULL, 0); } +// Obsolete +// void Renderer::drawByPath3(Mesh &t_mesh) { drawByPath3(t_mesh, NULL, 0); } /// --- Draw: PATH1 -void Renderer::draw(Mesh *t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount) +void Renderer::draw(Mesh **t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount) { - for (u16 i = 0; i < t_amount; i++) - draw(t_meshes[i], t_bulbs, t_bulbsCount); + beginFrameIfNeeded(); + if (!t_meshes[0]->isDataLoaded()) + PRINT_ERR("Can't draw, because no mesh data was loaded!"); + else if ( + t_amount >= 3 && + !t_meshes[0]->shouldBeBackfaceCulled && + t_meshes[0]->getFramesCount() == 1 && + t_meshes[0]->getMaterialsCount() == 1 && + t_meshes[0]->getFrame(0).getVertexCount() <= 96) + { + vifSender->disableWait(); + Mesh **meshesInFrustum = new Mesh *[t_amount]; + u16 addedMeshes = 0; + for (u16 i = 0; i < t_amount; i++) + if (t_meshes[i]->getMaterial(0).isInFrustum(renderData.frustumPlanes, t_meshes[i]->position)) + meshesInFrustum[addedMeshes++] = t_meshes[i]; + draw(*meshesInFrustum[0], t_bulbs, t_bulbsCount); + draw(*meshesInFrustum[1], t_bulbs, t_bulbsCount); + vifSender->enableWait(); + resetWaitFlag(); + vifSender->drawTheSameWithOtherMatrices(renderData, meshesInFrustum, 2, addedMeshes); + if (isWaitFlagSet()) + resetWaitFlag(); + else + waitForRender(); + delete[] meshesInFrustum; + } + else + for (u16 i = 0; i < t_amount; i++) + draw(*t_meshes[i], t_bulbs, t_bulbsCount); } void Renderer::draw(Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount) { beginFrameIfNeeded(); - vifSender->sendMatrices(renderData, t_mesh.position, t_mesh.rotation); + vifSender->calcMatrix(renderData, t_mesh.position, t_mesh.rotation); if (!t_mesh.isDataLoaded()) PRINT_ERR("Can't draw, because no mesh data was loaded!"); - Vector3 rotatedCamera = Vector3(*renderData.cameraPosition); - rotatedCamera.rotate(t_mesh.rotation, true); + camRotation.identity(); + camRotation.rotate(-t_mesh.rotation); + Vector3 rotatedCamera = Vector3(camRotation * *renderData.cameraPosition); if (t_mesh.getCurrentAnimationFrame() != t_mesh.getNextAnimationFrame()) t_mesh.animate(); for (u32 i = 0; i < t_mesh.getMaterialsCount(); i++) { - if (t_mesh.shouldBeFrustumCulled && !t_mesh.getMaterial(i).isInFrustum(renderData.frustumPlanes, t_mesh.position)) + MeshMaterial *material = &t_mesh.getMaterial(i); + if (t_mesh.shouldBeFrustumCulled && !material->isInFrustum(renderData.frustumPlanes, t_mesh.position)) return; - u32 vertCount = t_mesh.getMaterial(i).getFacesCount(); - VECTOR __attribute__((aligned(16))) vertices[vertCount]; - VECTOR __attribute__((aligned(16))) normals[vertCount]; - VECTOR __attribute__((aligned(16))) coordinates[vertCount]; - Texture *tex = textureRepo.getByMesh(t_mesh.getId(), t_mesh.getMaterial(i).getId()); + u32 vertCount = material->getFacesCount(); + VECTOR vertices[vertCount] __attribute__((aligned(16))); + VECTOR normals[vertCount] __attribute__((aligned(16))); + VECTOR coordinates[vertCount] __attribute__((aligned(16))); + Texture *tex = textureRepo.getBySpriteOrMesh(material->getId()); changeTexture(tex); vertCount = t_mesh.getDrawData(i, vertices, normals, coordinates, rotatedCamera); - vifSender->drawMesh(&renderData, perspective, vertCount, vertices, normals, coordinates, t_mesh, t_bulbs, t_bulbsCount, &textureBuffer); + vifSender->drawMesh(&renderData, perspective, vertCount, vertices, normals, coordinates, t_mesh, t_bulbs, t_bulbsCount, &textureBuffer, &material->color, !material->areSTsPresent()); } } -void Renderer::draw(Mesh *t_meshes, u16 t_amount) { draw(t_meshes, t_amount, NULL, 0); } +void Renderer::draw(Mesh **t_meshes, u16 t_amount) { draw(t_meshes, t_amount, NULL, 0); } void Renderer::draw(Mesh &t_mesh) { draw(t_mesh, NULL, 0); } @@ -305,7 +342,7 @@ 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.view = t_worldView; renderData.cameraPosition = t_cameraPos; renderData.frustumPlanes = t_planes; } diff --git a/src/engine/modules/texture_repository.cpp b/src/engine/modules/texture_repository.cpp index 44112be..2b4f816 100644 --- a/src/engine/modules/texture_repository.cpp +++ b/src/engine/modules/texture_repository.cpp @@ -57,7 +57,7 @@ void TextureRepository::addByMesh(char *t_path, Mesh &mesh, TextureFormat t_form else pngLoader.load(*texture, t_path, mesh.getMaterial(i).getName(), ".png"); texture->setName(mesh.getMaterial(i).getName()); - texture->addLink(mesh.getId(), mesh.getMaterial(i).getId()); + texture->addLink(mesh.getMaterial(i).getId()); textures.push_back(texture); } } diff --git a/src/engine/modules/vif_sender.cpp b/src/engine/modules/vif_sender.cpp index 2ef738a..b078fd9 100644 --- a/src/engine/modules/vif_sender.cpp +++ b/src/engine/modules/vif_sender.cpp @@ -17,8 +17,10 @@ #include "../include/utils/debug.hpp" const u32 VU1_PACKAGE_VERTS_PER_BUFF = 96; // Remember to modify buffer size in vu1 also -const u32 VU1_PACKAGES_PER_PACKET = 6; -const u32 VU1_PACKET_SIZE = 128; +const u32 VU1_PACKAGES_PER_PACKET = 9; +const u32 VU1_PACKET_SIZE = 256; // should be 128, but 256 is more safe for future +const u8 VU1_PARAMS_ADDRESS = 4; +const u8 VU1_RGBA_ADDRESS = 8; // ---- // Constructors/Destructors @@ -31,24 +33,24 @@ extern u32 VU1Draw3D_CodeEnd __attribute__((section(".vudata"))); VifSender::VifSender(Light *t_light) { - light = t_light; PRINT_LOG("Initializing VifSender"); - PRINT_LOG("VifSender initialized!"); + light = t_light; + lastVertCount = 0; + isDrawWaitEnabled = true; dma_channel_initialize(DMA_CHANNEL_VIF1, NULL, 0); dma_channel_fast_waits(DMA_CHANNEL_VIF1); uploadMicroProgram(); packets[0] = packet2_create(VU1_PACKET_SIZE, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); packets[1] = packet2_create(VU1_PACKET_SIZE, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); - matricesPacket = packet2_create(4, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); context = 0; - setDoubleBuffer(); + setDoubleBufferAddStaticData(); + PRINT_LOG("VifSender initialized!"); } VifSender::~VifSender() { packet2_free(packets[0]); packet2_free(packets[1]); - packet2_free(matricesPacket); } // ---- @@ -69,27 +71,19 @@ void VifSender::uploadMicroProgram() packet2_free(packet2); } -void VifSender::sendMatrices(const RenderData &t_renderData, const Vector3 &t_position, const Vector3 &t_rotation) +void VifSender::calcMatrix(const RenderData &t_renderData, const Vector3 &t_position, const Vector3 &t_rotation) { - vec3ToNative(position, t_position, 1.0F); - vec3ToNative(rotation, t_rotation, 1.0F); - MATRIX localWorld, localScreen; - create_local_world(localWorld, position, rotation); - create_local_screen(localScreen, localWorld, t_renderData.worldView->data, t_renderData.perspective->data); - // Small undo, because im testing new matrix funcs, which are DIFFERENT than PS2SDK, so cant be used right now. - // Matrix viewProj = Matrix(); - // viewProj.rotation(t_rotation); // model matrix - // viewProj.translate(t_position); // model matrix - // viewProj *= *t_renderData.worldView * *t_renderData.perspective; // viewproj = model * (view * projection) - packet2_reset(matricesPacket, false); - // packet2_utils_vu_add_unpack_data(matricesPacket, 0, &viewProj.data, 8, 0); - packet2_utils_vu_add_unpack_data(matricesPacket, 0, localScreen, 8, 0); - packet2_utils_vu_add_end_tag(matricesPacket); - dma_channel_wait(DMA_CHANNEL_VIF1, 0); - dma_channel_send_packet2(matricesPacket, DMA_CHANNEL_VIF1, 1); + model.identity(); + model.rotate(t_rotation); + model.translate(t_position); + + modelViewProj.identity(); + modelViewProj = model * modelViewProj; + modelViewProj = *t_renderData.view * modelViewProj; + modelViewProj = *t_renderData.projection * modelViewProj; } -void VifSender::drawMesh(RenderData *t_renderData, Matrix t_perspective, u32 vertCount2, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount, texbuffer_t *textureBuffer) +void VifSender::drawMesh(RenderData *t_renderData, Matrix t_perspective, u32 vertCount2, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount, texbuffer_t *textureBuffer, color_t *t_color, u8 t_rgbaOnly) { // we have to split 3D object into small parts, because of small memory of VU1 @@ -103,7 +97,7 @@ void VifSender::drawMesh(RenderData *t_renderData, Matrix t_perspective, u32 ver 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, coordinates, t_renderData->prim, textureBuffer); + drawVertices(t_mesh, i, endI, vertices, coordinates, t_renderData->prim, textureBuffer, isDrawWaitEnabled ? endI == vertCount2 : false, t_color, t_rgbaOnly); if (endI == vertCount2) // if there are no more vertices to draw, break { i = vertCount2; @@ -119,82 +113,138 @@ void VifSender::drawMesh(RenderData *t_renderData, Matrix t_perspective, u32 ver } } -void VifSender::setDoubleBuffer() +void VifSender::setDoubleBufferAddStaticData() { - packet2_t *settings = packet2_create(2, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); - packet2_utils_vu_add_double_buffer(settings, 8, 496); + packet2_t *settings = packet2_create(10, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + packet2_utils_vu_open_unpack(settings, 0, false); + { + packet2_utils_gs_add_draw_finish_giftag(settings); + packet2_utils_gif_add_set(settings, 1); + } + packet2_utils_vu_close_unpack(settings); + packet2_utils_vu_add_double_buffer(settings, 10, 498); packet2_utils_vu_add_end_tag(settings); - dma_channel_send_packet2(settings, DMA_CHANNEL_VIF1, 1); + dma_channel_send_packet2(settings, DMA_CHANNEL_VIF1, true); dma_channel_wait(DMA_CHANNEL_VIF1, 0); packet2_free(settings); } /** Draw using PATH1 */ -void VifSender::drawVertices(Mesh &t_mesh, u32 t_start, u32 t_end, VECTOR *t_vertices, VECTOR *t_coordinates, prim_t *t_prim, texbuffer_t *textureBuffer) +void VifSender::drawVertices(Mesh &t_mesh, u32 t_start, u32 t_end, VECTOR *t_vertices, VECTOR *t_coordinates, prim_t *t_prim, texbuffer_t *t_texBuff, u8 t_addDrawWait, color_t *t_color, u8 t_rgbaOnly) { const u32 vertCount = t_end - t_start; - u32 vif_added_bytes = 0; - packet2_utils_vu_open_unpack(currPacket, 0, 1); - // TODO get this via screensettings - packet2_add_float(currPacket, 2048.0F); // scale - packet2_add_float(currPacket, 2048.0F); // scale - packet2_add_float(currPacket, ((float)0xFFFFFF) / 32.0F); // scale - packet2_add_u32(currPacket, vertCount); // vertex count - packet2_utils_gif_add_set(currPacket, 1); + lastVertCount = vertCount; + isLastRGBAOnly = t_rgbaOnly; + packet2_utils_vu_open_unpack(currPacket, 0, true); + packet2_add_data(currPacket, modelViewProj.data, 4); + packet2_add_u32(currPacket, t_addDrawWait); // Draw finish? + packet2_add_u32(currPacket, vertCount); // Vertex count + packet2_add_u32(currPacket, vertCount / 3); // Triangles count + packet2_add_u32(currPacket, t_rgbaOnly); // 0 = STQ+RGBA, 1 = RGBA packet2_utils_gs_add_lod(currPacket, &t_mesh.lod); - packet2_utils_gs_add_texbuff_clut(currPacket, textureBuffer, &t_mesh.clut); - packet2_utils_gs_add_prim_giftag(currPacket, t_prim, vertCount, DRAW_STQ2_REGLIST, 3, 0); - - packet2_add_u32(currPacket, t_mesh.color.r); - packet2_add_u32(currPacket, t_mesh.color.g); - packet2_add_u32(currPacket, t_mesh.color.b); - packet2_add_u32(currPacket, t_mesh.color.a); - - // Clipping tests start - - // // const float minZ = 1; - // // const float maxZ = 65535; - // // const int iGuardDimXY = 2048; - - // // vu1.addFloat(1.0F); // f_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; - // // // F_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 - - packet2_add_float(currPacket, 0.0F); - packet2_add_float(currPacket, 0.0F); - packet2_add_float(currPacket, 0.0F); - packet2_add_float(currPacket, 0.0F); - - //// Clipping tests end - vif_added_bytes += packet2_utils_vu_close_unpack(currPacket); - packet2_utils_vu_add_unpack_data(currPacket, vif_added_bytes, t_vertices + t_start, vertCount, 1); - vif_added_bytes += vertCount; - packet2_utils_vu_add_unpack_data(currPacket, vif_added_bytes, t_coordinates + t_start, vertCount, 1); - vif_added_bytes += vertCount; + packet2_utils_gs_add_texbuff_clut(currPacket, t_texBuff, &t_mesh.clut); + if (t_rgbaOnly) + packet2_utils_gs_add_prim_giftag(currPacket, t_prim, vertCount, DRAW_RGBAQ_REGLIST, 2, 0); + else + packet2_utils_gs_add_prim_giftag(currPacket, t_prim, vertCount, DRAW_STQ2_REGLIST, 3, 0); + packet2_add_u32(currPacket, t_color->r); + packet2_add_u32(currPacket, t_color->g); + packet2_add_u32(currPacket, t_color->b); + packet2_add_u32(currPacket, t_color->a); + u32 vif_added_bytes = packet2_utils_vu_close_unpack(currPacket); + packet2_utils_vu_add_unpack_data(currPacket, vif_added_bytes, t_vertices + t_start, vertCount, true); + if (!t_rgbaOnly) + { + vif_added_bytes += vertCount; + packet2_utils_vu_add_unpack_data(currPacket, vif_added_bytes, t_coordinates + t_start, vertCount, true); + } packet2_utils_vu_add_start_program(currPacket, 0); } + +void VifSender::drawTheSameWithOtherMatrices(const RenderData &t_renderData, Mesh **t_meshes, const u32 &t_skip, const u32 &t_count) +{ + // Standard double buffering (packets) + packet2_t *packet1 = packet2_create(300, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + packet2_t *packet2 = packet2_create(300, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + packet2_t *currMPacket = packet1; + u8 currPacketIndex = 1; + + // We are sending 32 matrices max per one VU1 send + u8 switchCounter = 0; + for (u32 i = t_skip; i < t_count; i++) + { + model.identity(); + model.rotate(t_meshes[i]->rotation); + model.translate(t_meshes[i]->position); + + modelViewProj.identity(); + modelViewProj = model * modelViewProj; + modelViewProj = *t_renderData.view * modelViewProj; + modelViewProj = *t_renderData.projection * modelViewProj; + + packet2_utils_vu_open_unpack(currMPacket, 0, true); + { + packet2_add_data(currMPacket, modelViewProj.data, 4); + } + packet2_utils_vu_close_unpack(currMPacket); + packet2_utils_vu_open_unpack(currMPacket, VU1_RGBA_ADDRESS, true); + { + packet2_add_u32(currMPacket, t_meshes[i]->getMaterial(0).color.r); + packet2_add_u32(currMPacket, t_meshes[i]->getMaterial(0).color.g); + packet2_add_u32(currMPacket, t_meshes[i]->getMaterial(0).color.b); + packet2_add_u32(currMPacket, t_meshes[i]->getMaterial(0).color.a); + } + packet2_utils_vu_close_unpack(currMPacket); + + if (i != t_count - 1) // if it is last, we must also add draw wait finish interrupt. + packet2_utils_vu_add_start_program(currMPacket, 0); + + if (switchCounter++ >= 32) + { + switchCounter = 0; + if (i == t_count - 1) // is last + { + packet2_utils_vu_open_unpack(currMPacket, VU1_PARAMS_ADDRESS, true); + { + packet2_add_u32(currMPacket, true); // Draw wait finish? + packet2_add_u32(currMPacket, lastVertCount); // Vertex count + packet2_add_u32(currMPacket, lastVertCount / 3); // Triangles count + packet2_add_u32(currMPacket, isLastRGBAOnly); // 0 = STQ+RGBA, 1 = RGBA + } + packet2_utils_vu_close_unpack(currMPacket); + packet2_utils_vu_add_start_program(currMPacket, 0); // and start program + } + packet2_utils_vu_add_end_tag(currMPacket); + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(currMPacket, DMA_CHANNEL_VIF1, 1); + if (currPacketIndex == 1) // Switch double buffer (packets) + { + currPacketIndex = 2; + currMPacket = packet2; + } + else + { + currPacketIndex = 1; + currMPacket = packet1; + } + packet2_reset(currMPacket, false); + } + } + if (switchCounter != 0) // if there are any not sended matrices + { + packet2_utils_vu_open_unpack(currMPacket, VU1_PARAMS_ADDRESS, true); + { + packet2_add_u32(currMPacket, true); // Draw wait finish? + packet2_add_u32(currMPacket, lastVertCount); // Vertex count + packet2_add_u32(currMPacket, lastVertCount / 3); // Triangles count + packet2_add_u32(currMPacket, isLastRGBAOnly); // 0 = STQ+RGBA, 1 = RGBA + } + packet2_utils_vu_close_unpack(currMPacket); + packet2_utils_vu_add_start_program(currMPacket, 0); + packet2_utils_vu_add_end_tag(currMPacket); + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(currMPacket, DMA_CHANNEL_VIF1, 1); + } + packet2_free(packet1); + packet2_free(packet2); +} diff --git a/src/engine/utils/math.cpp b/src/engine/utils/math.cpp index 5c4846e..e9bd11d 100644 --- a/src/engine/utils/math.cpp +++ b/src/engine/utils/math.cpp @@ -11,7 +11,6 @@ #include "../include/utils/math.hpp" #include -#include float Math::cos(float x) { @@ -72,16 +71,6 @@ float Math::cos(float x) 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 */ diff --git a/src/engine/utils/string.cpp b/src/engine/utils/string.cpp index d928673..60381c3 100644 --- a/src/engine/utils/string.cpp +++ b/src/engine/utils/string.cpp @@ -11,6 +11,7 @@ #include "../include/utils/string.hpp" #include "../include/utils/debug.hpp" #include +#define CHAR_BIT 8 char *String::createU32ToString(u32 a) { diff --git a/src/engine/vu1_progs/draw3D.vcl b/src/engine/vu1_progs/draw3D.vcl deleted file mode 100644 index 777d84f..0000000 --- a/src/engine/vu1_progs/draw3D.vcl +++ /dev/null @@ -1,154 +0,0 @@ -; ______ ____ ___ -; | \/ ____| |___| -; | | | \ | | -;--------------------------- -; Copyright 2020, tyra - https://github.com/h4570/tyra -; Sandro Sobczyński -; -;--------------------------------------------------------------- -; 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 diff --git a/src/engine/vu1_progs/draw3D.vclpp b/src/engine/vu1_progs/draw3D.vclpp new file mode 100644 index 0000000..7cbe82a --- /dev/null +++ b/src/engine/vu1_progs/draw3D.vclpp @@ -0,0 +1,190 @@ +; ______ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------- +; Copyright 2020, tyra - https://github.com/h4570/tyra +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; draw3D.vcl | +;--------------------------------------------------------------- +; First tyra VU1 microprogram. | +; Features: | +; - Draw triangles (no strip) with STQ (textures) and 1 RGBA. | +; This program uses double buffering (xtop) | +; | +; I want to say thank you to: | +; - Dr Henry Fortuna - for teaching how things work | +; - Jesper Svennevid, Daniel Collin - for openvcl samples | +; - Guilherme Lampert - for VU1 idea for PS2 Quake and vclpp | +; - Tyler Daniel - for PS2GL source code for PS2 Linux | +;--------------------------------------------------------------- + +; TODO +; - Add dynamic lighting (feature) +; - Add --cont + MSCNT instead of alltime MSCAL +; - Split this program into two (RBA/STQ), so we can get better performance + +#include "/repos/tyra/src/engine/vu1_progs/geometry.inc" +#include "/repos/tyra/src/engine/vu1_progs/matrix.inc" +#include "/repos/tyra/src/engine/vu1_progs/vector.inc" + +#vuprog draw3D + +.syntax new +.name VU1Draw3D +.vu +.init_vf_all +.init_vi_all + +--enter +--endenter + +;///////////// LOAD STATIC DATA ///////////// +lq gif_draw_finish_tag, 0(vi00) ; GIF tag - wait +lq gif_set_tag, 1(vi00) ; GIF tag - set +;//////////////////////////////////////////// + +xtop double_buffer + +;//////// LOAD CURRENT BUFFER DATA ////////// +MatrixLoad{ matrix, 0, double_buffer } +ilw.x do_draw_finish, 4(double_buffer) ; Add draw finish tag? (sync) +ilw.y vertex_count, 4(double_buffer) ; Vertex count +ilw.z triangles_count, 4(double_buffer) ; Triangles count +ilw.w rgba_only, 4(double_buffer) ; RGBA (1) or STQ+RGBA (0) +lq tex_gif_tag_1, 5(double_buffer) ; GIF tag - texture LOD +lq tex_gif_tag_2, 6(double_buffer) ; GIF tag - texture buffer & CLUT +lq prim_tag, 7(double_buffer) ; GIF tag - tell GS how many data we will send +lq rgba, 8(double_buffer) ; Mesh RGBA + +iaddiu vertex_data, double_buffer, 9 ; pointer to vertex data +iadd stq_data, vertex_data, vertex_count ; pointer to stq +iadd kick_address, stq_data, vertex_count ; pointer for XGKICK +iadd dest_address, stq_data, vertex_count ; helper pointer for data inserting +;//////////////////////////////////////////// + +LoadScaleConstant{ gs_scale } +fcset 0x000000 ; VCL won't let us use CLIP without first zeroing the clip flags + +;/////////////// STORE TAGS ///////////////// +sqi gif_set_tag, (dest_address++) ; +sqi tex_gif_tag_1, (dest_address++) ; texture LOD tag +sqi gif_set_tag, (dest_address++) ; +sqi tex_gif_tag_2, (dest_address++) ; texture buffer & CLUT tag +iblez do_draw_finish, prim_tag_l +sqi gif_set_tag, (dest_address++) ; +sqi gif_draw_finish_tag, (dest_address++) ; do draw_finish is needed +prim_tag_l: +sqi prim_tag, (dest_address++) ; prim + tell gs how many data will be +;//////////////////////////////////////////// + +;//////// FIX ADC BIT FOR CLIPPING ////////// +iaddiu adc_bit, vi00, 0x7FFF +iaddiu adc_bit, adc_bit, 1 +;//////////////////////////////////////////// + +;/////////// START TRIANGLE LOOP //////////// +iaddiu triangle_counter, vi00, 0 ; Reset counter +triangle_loop: --LoopCS 1,3 + + ;//////////////// VERTEX 1 ////////////////// + vec1: + VectorLoad{ vertex, vertex_data, 0 } + MatrixXForm{ xformed_vertex, matrix, vertex } + VectorClip{ gs_vertex, xformed_vertex } + VectorPerspectiveDivide{ xformed_vertex } + VectorAddGSScales{ gs_vertex, xformed_vertex, gs_scale } + + ibgtz rgba_only, vec_1_rgba + + vec_1_stq_rgba: + VectorLoad{ stq1, stq_data, 0 } + VectorTexturePerspectiveCorrection{ pers_stq, stq1 } + VectorStore{ pers_stq, dest_address, 0 } + VectorStore{ rgba, dest_address, 1 } + VectorStore{ gs_vertex, dest_address, 2 } + ibeq vi00, vi00, vec2 + + vec_1_rgba: + VectorStore{ rgba, dest_address, 0 } + VectorStore{ gs_vertex, dest_address, 1 } + + ;//////////////////////////////////////////// + + ;//////////////// VERTEX 2 ////////////////// + vec2: + VectorLoad{ vertex, vertex_data, 1 } + MatrixXForm{ xformed_vertex, matrix, vertex } + VectorClip{ gs_vertex, xformed_vertex } + VectorPerspectiveDivide{ xformed_vertex } + VectorAddGSScales{ gs_vertex, xformed_vertex, gs_scale } + + ibgtz rgba_only, vec_2_rgba + + vec_2_stq_rgba: + VectorLoad{ stq2, stq_data, 1 } + VectorTexturePerspectiveCorrection{ pers_stq, stq2 } + VectorStore{ pers_stq, dest_address, 3 } + VectorStore{ rgba, dest_address, 4 } + VectorStore{ gs_vertex, dest_address, 5 } + ibeq vi00, vi00, vec3 + + vec_2_rgba: + VectorStore{ rgba, dest_address, 2 } + VectorStore{ gs_vertex, dest_address, 3 } + + ;//////////////////////////////////////////// + + ;//////////////// VERTEX 3 ////////////////// + vec3: + VectorLoad{ vertex, vertex_data, 2 } + MatrixXForm{ xformed_vertex, matrix, vertex } + VectorClip{ gs_vertex, xformed_vertex } + VectorPerspectiveDivide{ xformed_vertex } + VectorAddGSScales{ gs_vertex, xformed_vertex, gs_scale } + + fcand vi01, 0x03FFFF + iaddiu new_adc_bit, vi01, 0x7FFF + mfir.w gs_vertex, new_adc_bit + + ibgtz rgba_only, vec_3_rgba + + vec_3_stq_rgba: + VectorLoad{ stq3, stq_data, 2 } + VectorTexturePerspectiveCorrection{ pers_stq, stq3 } + VectorStore{ pers_stq, dest_address, 6 } + VectorStore{ rgba, dest_address, 7 } + VectorStore{ gs_vertex, dest_address, 8 } + iaddiu dest_address, dest_address, 9 // Loop control + ibeq vi00, vi00, loop_ctrl + + vec_3_rgba: + VectorStore{ rgba, dest_address, 4 } + VectorStore{ gs_vertex, dest_address, 5 } + iaddiu dest_address, dest_address, 6 // Loop control + + ;//////////////////////////////////////////// + + ;////////////// LOOP CONTROL //////////////// + loop_ctrl: + iaddiu vertex_data, vertex_data, 3 + iaddiu stq_data, stq_data, 3 + + iaddiu triangle_counter, triangle_counter, 1 // Incrementing this + // by other value than 1 is causing HUGE problems, but.. why? + // My first idea was do vertex_counter and incrementing by 3 + ibne triangle_counter, triangles_count, triangle_loop + ;//////////////////////////////////////////// + +;//////////////////////////////////////////// + +--barrier + + +xgkick kick_address ; dispatch to the GS rasterizer. + +--exit +--endexit + +#endvuprog \ No newline at end of file diff --git a/src/engine/vu1_progs/draw3D.vsm b/src/engine/vu1_progs/draw3D.vsm index f8c1e0e..b1c0afa 100644 --- a/src/engine/vu1_progs/draw3D.vsm +++ b/src/engine/vu1_progs/draw3D.vsm @@ -11,63 +11,137 @@ .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 +; _LNOPT_w=[ normal2 ] 27 [27 0] 27 [__v_draw3D_vcl_4] + NOP xtop VI06 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 lq VF01,0(VI00) + NOP ilw.x VI01,4(VI06) + NOP ilw.y VI08,4(VI06) + NOP lq VF03,0(VI06) + NOP lq VF04,1(VI06) + NOP lq VF08,5(VI06) + NOP lq VF10,6(VI06) + NOP lq VF05,2(VI06) + NOP lq VF06,3(VI06) + NOP iaddiu VI04,VI06,0x00000009 + NOP iadd VI05,VI04,VI08 + NOP ilw.z VI02,4(VI06) + NOP iadd VI07,VI05,VI08 + NOP loi 0x44fff000 + NOP ilw.w VI03,4(VI06) + NOP lq VF07,7(VI06) + NOP sqi VF02,(VI07++) + NOP sqi VF08,(VI07++) + NOP sqi VF02,(VI07++) + NOP lq VF08,8(VI06) + NOP iadd VI06,VI05,VI08 + addi.xy VF09,VF00,I loi 0x492aaaaa 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 iblez VI01,prim_tag_l + addi.z VF09,VF00,I sqi VF10,(VI07++) +; _LNOPT_w=[ normal2 ] 2 [2 0] 2 [__v_draw3D_vcl_5] + NOP sqi VF02,(VI07++) + NOP sqi VF01,(VI07++) +prim_tag_l: +; _LNOPT_w=[ normal2 ] 4 [4 0] 4 [prim_tag_l] + NOP iaddiu VI08,VI00,0x00007fff + NOP sqi VF07,(VI07++) + NOP iaddiu VI08,VI08,0x00000001 + NOP iaddiu VI09,VI00,0 +triangle_loop: +; _LNOPT_w=[ normal2 ] 11 [27 0] 27 [triangle_loop] + NOP lq VF02,0(VI04) + mulax ACC,VF03,VF02x mfir.w VF01,VI08 ; STALL_LATENCY ?3 + madday ACC,VF04,VF02y NOP + maddaz ACC,VF05,VF02z NOP + maddw VF02,VF06,VF02w NOP + clipw.xyz VF02xyz,VF02w div Q,VF00w,VF02w ; STALL_LATENCY ?3 + mulq.xyz VF02,VF02,Q waitq ; STALL_LATENCY ?6 + mulaw.xyz ACC,VF09,VF00w NOP + madd.xyz VF02,VF02,VF09 NOP ; STALL_LATENCY ?2 + NOP ibgtz VI03,vec_1_rgba + ftoi4.xyz VF01,VF02 NOP ; STALL_LATENCY ?2 +; _LNOPT_w=[ normal2 ] 5 [9 0] 9 [vec_1_stq_rgba] + NOP lq VF02,0(VI05) + mulq VF01,VF02,Q sq VF01,2(VI07) ; STALL_LATENCY ?3 + NOP sq VF08,1(VI07) + NOP b vec2 + NOP sq VF01,0(VI07) ; STALL_LATENCY ?1 +vec_1_rgba: +; _LNOPT_w=[ normal2 ] 4 [2 0] 4 [vec_1_rgba] NOP NOP NOP NOP + NOP sq VF08,0(VI07) + NOP sq VF01,1(VI07) +vec2: +; _LNOPT_w=[ normal2 ] 11 [27 0] 27 [vec2] + NOP lq VF02,1(VI04) + mulax ACC,VF03,VF02x mfir.w VF01,VI08 ; STALL_LATENCY ?3 + madday ACC,VF04,VF02y NOP + maddaz ACC,VF05,VF02z NOP + maddw VF02,VF06,VF02w NOP + clipw.xyz VF02xyz,VF02w div Q,VF00w,VF02w ; STALL_LATENCY ?3 + mulq.xyz VF02,VF02,Q waitq ; STALL_LATENCY ?6 + mulaw.xyz ACC,VF09,VF00w NOP + madd.xyz VF02,VF02,VF09 NOP ; STALL_LATENCY ?2 + NOP ibgtz VI03,vec_2_rgba + ftoi4.xyz VF01,VF02 NOP ; STALL_LATENCY ?2 +; _LNOPT_w=[ normal2 ] 5 [9 0] 9 [vec_2_stq_rgba] + NOP lq VF02,1(VI05) + mulq VF01,VF02,Q sq VF01,5(VI07) ; STALL_LATENCY ?3 + NOP sq VF08,4(VI07) + NOP b vec3 + NOP sq VF01,3(VI07) ; STALL_LATENCY ?1 +vec_2_rgba: +; _LNOPT_w=[ normal2 ] 4 [2 0] 4 [vec_2_rgba] NOP NOP NOP NOP + NOP sq VF08,2(VI07) + NOP sq VF01,3(VI07) +vec3: +; _LNOPT_w=[ normal2 ] 13 [27 0] 27 [vec3] + NOP lq VF01,2(VI04) + mulax ACC,VF03,VF01x NOP ; STALL_LATENCY ?3 + madday ACC,VF04,VF01y NOP + maddaz ACC,VF05,VF01z NOP + maddw VF01,VF06,VF01w NOP + clipw.xyz VF01xyz,VF01w div Q,VF00w,VF01w ; STALL_LATENCY ?3 + mulq.xyz VF01,VF01,Q waitq ; STALL_LATENCY ?6 + mulaw.xyz ACC,VF09,VF00w NOP + madd.xyz VF01,VF01,VF09 fcand VI01,262143 ; STALL_LATENCY ?2 + NOP iaddiu VI01,VI01,0x00007fff + NOP mfir.w VF01,VI01 + NOP ibgtz VI03,vec_3_rgba + ftoi4.xyz VF01,VF01 NOP +; _LNOPT_w=[ normal2 ] 6 [9 0] 9 [vec_3_stq_rgba] + NOP lq VF02,2(VI05) + mulq VF01,VF02,Q sq VF01,8(VI07) ; STALL_LATENCY ?3 + NOP sq VF08,7(VI07) + NOP iaddiu VI07,VI07,0x00000009 + NOP b loop_ctrl + NOP sq VF01,-3(VI07) +vec_3_rgba: +; _LNOPT_w=[ normal2 ] 4 [3 0] 4 [vec_3_rgba] 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 sq VF08,4(VI07) + NOP iaddiu VI07,VI07,0x00000006 + NOP sq VF01,-1(VI07) +loop_ctrl: +; _LNOPT_w=[ normal2 ] 4 [4 0] 4 [loop_ctrl] + NOP iaddiu VI09,VI09,0x00000001 + NOP iaddiu VI04,VI04,0x00000003 + NOP ibne VI09,VI02,triangle_loop + NOP iaddiu VI05,VI05,0x00000003 +; _LNOPT_w=[ normal2 ] 3 [1 0] 3 [__v_draw3D_vcl_21] + NOP xgkick VI06 NOP[E] NOP NOP NOP .align 4 VU1Draw3D_CodeEnd: -; iCount=47 +; iCount=103 ; register stats: -; 8 VU User integer -; 10 VU User floating point +; 10 VU User integer +; 11 VU User floating point ;------------------------- ;------------------------- ;------------------------- diff --git a/src/engine/vu1_progs/geometry.inc b/src/engine/vu1_progs/geometry.inc new file mode 100644 index 0000000..2562412 --- /dev/null +++ b/src/engine/vu1_progs/geometry.inc @@ -0,0 +1,7 @@ +; Load GS offsets to center xformed vertex in gs coord space and color clamping constant +#macro LoadScaleConstant: gs_scale + loi 2047.5 + addi.xy gs_scale, vf00, i + loi 699050.625000 // ((float)0xFFFFFF) / 24.0F + addi.z gs_scale, vf00, i +#endmacro diff --git a/src/engine/vu1_progs/matrix.inc b/src/engine/vu1_progs/matrix.inc new file mode 100644 index 0000000..47615e5 --- /dev/null +++ b/src/engine/vu1_progs/matrix.inc @@ -0,0 +1,13 @@ +#macro MatrixLoad: matrix, offset, vumem + lq matrix[0], offset+0(vumem) + lq matrix[1], offset+1(vumem) + lq matrix[2], offset+2(vumem) + lq matrix[3], offset+3(vumem) +#endmacro + +#macro MatrixXForm: output_vertex, matrix, input_vertex + mul acc, matrix[0], input_vertex[x] + madd acc, matrix[1], input_vertex[y] + madd acc, matrix[2], input_vertex[z] + madd output_vertex, matrix[3], input_vertex[w] +#endmacro diff --git a/src/engine/vu1_progs/vector.inc b/src/engine/vu1_progs/vector.inc new file mode 100644 index 0000000..c492916 --- /dev/null +++ b/src/engine/vu1_progs/vector.inc @@ -0,0 +1,27 @@ +#macro VectorPerspectiveDivide: vertex + div q, vf00[w], vertex[w] + mulq.xyz vertex, vertex, q +#endmacro + +#macro VectorAddGSScales: output_vertex, input_vertex, gs_scale + mula.xyz acc, gs_scale, vf00[w] + madd.xyz output_vertex, input_vertex, gs_scale + ftoi4.xyz output_vertex, output_vertex +#endmacro + +#macro VectorTexturePerspectiveCorrection: output_vertex, input_vertex + mulq output_vertex, input_vertex, q +#endmacro + +#macro VectorStore: vertex, vumem, num + sq vertex, num(vumem) +#endmacro + +#macro VectorClip: output_vertex, input_vertex + clipw.xyz input_vertex, input_vertex + mfir.w output_vertex, adc_bit +#endmacro + +#macro VectorLoad: output_vertex, vumem, offset + lq output_vertex, offset(vumem) +#endmacro diff --git a/src/samples/dolphin/README.MD b/src/samples/dolphin/README.MD new file mode 100644 index 0000000..884ccc5 --- /dev/null +++ b/src/samples/dolphin/README.MD @@ -0,0 +1,20 @@ +## Dolphin sample + +### Features +- Animated character +- Collectibles and mines +- Big DFF mesh +- Background songs +- Overlay +- Audio effects (ADPCM) +- Transparent 2D UI +- Usage of draw() in array mode (for water tiles, very fast) + +### Assets +[Download](http://apgcglz.cluster028.hosting.ovh.net/tyra/1.31.2/samples/dolphin/assets.zip) + +### Screenshot + +[![Dolphin screenshot][dolphin-screenshot]](#) + +[dolphin-screenshot]: http://apgcglz.cluster028.hosting.ovh.net/tyra/1.31.2/samples/dolphin/dolphin.gif diff --git a/src/samples/dolphin/camera.cpp b/src/samples/dolphin/camera.cpp index 5c122f7..69d8669 100755 --- a/src/samples/dolphin/camera.cpp +++ b/src/samples/dolphin/camera.cpp @@ -12,14 +12,11 @@ #include -const float CAMERA_Y = 15.0F; +const float CAMERA_Y = 25.0F; -Camera::Camera(ScreenSettings *t_screen) : CameraBase(t_screen, &position, &up) +Camera::Camera(ScreenSettings *t_screen) : CameraBase(t_screen, &position) { verticalLevel = 30.0F; - up.x = 0.0F; - up.y = 1.0F; - up.z = 0.0F; } Camera::~Camera() {} @@ -43,12 +40,7 @@ void Camera::rotate(Pad &t_pad) horizontalLevel -= 0.08; else if (t_pad.rJoyH >= 200) horizontalLevel += 0.08; - /* - 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); @@ -59,15 +51,4 @@ 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; - } } \ No newline at end of file diff --git a/src/samples/dolphin/camera.hpp b/src/samples/dolphin/camera.hpp index 7bcbde3..d13d38c 100755 --- a/src/samples/dolphin/camera.hpp +++ b/src/samples/dolphin/camera.hpp @@ -22,7 +22,7 @@ class Camera : public CameraBase { public: - Vector3 position,up, unitCirclePosition; + Vector3 position, up, unitCirclePosition; float horizontalLevel, verticalLevel; Camera(ScreenSettings *t_screen); @@ -34,7 +34,6 @@ public: protected: Vector3 *getPosition() { return &position; }; - Vector3 *getUp() { return &up; }; ScreenSettings screen; }; diff --git a/src/samples/dolphin/dolphin.cpp b/src/samples/dolphin/dolphin.cpp index 6471834..fb19346 100755 --- a/src/samples/dolphin/dolphin.cpp +++ b/src/samples/dolphin/dolphin.cpp @@ -11,14 +11,12 @@ #include "dolphin.hpp" #include "utils/math.hpp" -const u8 WATER_TILE_SCALE = 5; -const u8 WATER_SIZE = 100; - +float Dolphin::engineFPS = 60.0F; +const float WATER_TILE_SCALE = 6.0F; +const u8 WATER_SIZE = 4; const u8 MINES_COUNT = 15; const u8 OYSTERS_COUNT = 5; -float Dolphin::engineFPS = 60.F; - Dolphin::Dolphin(Engine *t_engine) : engine(t_engine), camera(&engine->screen) { oysters = new Collectible[OYSTERS_COUNT]; @@ -29,12 +27,13 @@ Dolphin::~Dolphin() { delete[] oysters; delete[] mines; + delete[] waterDrawList; } void Dolphin::onInit() { player.init(engine); - engine->renderer->setCameraDefinitions(&camera.worldView, &camera.position, camera.planes); + engine->renderer->setCameraDefinitions(&camera.view, &camera.position, camera.planes); engine->audio.loadSong("sound/dirediredocks.wav"); engine->audio.playSong(); @@ -73,11 +72,25 @@ void Dolphin::onInit() printf("Loaded.\n"); printf("Loading water...\n"); - water.loadObj("water/", "water", WATER_TILE_SCALE, false); - water.position.set(0, WATER_LEVEL, 0); - texRepo->addByMesh("water/", water, BMP); - water.shouldBeFrustumCulled = false; - water.shouldBeBackfaceCulled = false; + + u32 spiralOffset = (u32)sqrt(WATER_TILES_COUNT); + waterDrawList = new Mesh *[WATER_TILES_COUNT]; + calcSpiral(spiralOffset, spiralOffset); + water[0].loadObj("water/", "water", WATER_TILE_SCALE, false); + water[0].position.set(0.0F, WATER_LEVEL, 0.0F); + texRepo->addByMesh("water/", water[0], BMP); + water[0].shouldBeFrustumCulled = true; + water[0].shouldBeBackfaceCulled = false; + waterDrawList[0] = &water[0]; + for (size_t i = 1; i < WATER_TILES_COUNT; i++) + { + water[i].loadFrom(water[0]); + water[i].shouldBeFrustumCulled = true; + water[i].shouldBeBackfaceCulled = false; + water[i].position.set(WATER_TILE_SCALE * 2.0F * spirals[i].x, WATER_LEVEL, WATER_TILE_SCALE * 2.0F * spirals[i].y); + texRepo->getBySpriteOrMesh(water[0].getMaterial(0).getId())->addLink(water[i].getMaterial(0).getId()); + waterDrawList[i] = &water[i]; + } printf("Loading seabed...\n"); seabed.loadObj("seabed/", "seabed", 10.0F, false); @@ -96,7 +109,6 @@ void Dolphin::onInit() waterbox.position.y = -100.F; printf("Loading oyster dff\n"); - //oysters[0].loadDff("oyster/", "oyster", 1.F, false); oysters[0].mesh.loadObj("oyster/", "oyster", 10.F, false); printf("Loaded."); oysters[0].mesh.shouldBeBackfaceCulled = false; @@ -110,14 +122,12 @@ void Dolphin::onInit() oysters[i].mesh.loadFrom(oysters[0].mesh); oysters[i].mesh.shouldBeBackfaceCulled = false; oysters[i].mesh.shouldBeFrustumCulled = false; - texRepo->getByMesh(oysters[0].mesh.getId(), oysters[0].mesh.getMaterial(0).getId()) - ->addLink(oysters[i].mesh.getId(), oysters[i].mesh.getMaterial(0).getId()); + texRepo->getBySpriteOrMesh(oysters[0].mesh.getMaterial(0).getId())->addLink(oysters[i].mesh.getMaterial(0).getId()); oysters[i].mesh.position.set(i * -100, 5.0F, i * -100); } printf("Loading mine .obj\n"); mines[0].mesh.loadObj("mine/", "mine", 10.F, false); - printf("Loaded."); mines[0].mesh.shouldBeBackfaceCulled = false; mines[0].mesh.shouldBeFrustumCulled = false; mines[0].mesh.position.set(5, -15, 32); @@ -129,13 +139,13 @@ void Dolphin::onInit() mines[i].mesh.loadFrom(mines[0].mesh); mines[i].mesh.shouldBeBackfaceCulled = false; mines[i].mesh.shouldBeFrustumCulled = false; - texRepo->getByMesh(mines[0].mesh.getId(), mines[0].mesh.getMaterial(0).getId()) - ->addLink(mines[i].mesh.getId(), mines[i].mesh.getMaterial(0).getId()); + texRepo->getBySpriteOrMesh(mines[0].mesh.getMaterial(0).getId())->addLink(mines[i].mesh.getMaterial(0).getId()); mines[i].mesh.position.set(i * -10, 0.0F, i * -68); } Texture *pLifeTex = texRepo->add("2d/", "life", PNG); - //pLifeTex->addLink(lifeSprites[0].getId()); + // pLifeTex->addLink(lifeSprites[0].getId()); + for (int i = 0; i < 3; i++) { lifeSprites[i].size.set(64.0F, 64.0F); @@ -164,12 +174,13 @@ void Dolphin::onUpdate() engine->renderer->draw(gameOver); return; } - Dolphin::engineFPS = engine->fps; - if (engine->pad.isCrossClicked) - printf("Delta multiplier: %f\n", 60.0F / engine->fps); - float xDist = player.mesh.position.x - water.position.x; - float zDist = player.mesh.position.z - water.position.z; + Dolphin::engineFPS = engine->fps; + // if (engine->pad.isCrossClicked) + // printf("Delta multiplier: %f\n", 60.0F / engine->fps); + + float xDist = player.mesh.position.x - water[0].position.x; + float zDist = player.mesh.position.z - water[0].position.z; if (xDist < 0) xDist *= -1; if (zDist < 0) @@ -177,8 +188,11 @@ void Dolphin::onUpdate() if (xDist > WATER_SIZE * WATER_TILE_SCALE / 4 || zDist > WATER_SIZE * WATER_TILE_SCALE / 4) { - water.position.x = (player.mesh.position.x / WATER_SIZE) * WATER_SIZE; - water.position.z = (player.mesh.position.z / WATER_SIZE) * WATER_SIZE; + for (size_t i = 0; i < WATER_TILES_COUNT; i++) + { + water[i].position.x = player.mesh.position.x + (WATER_TILE_SCALE * 2.0F * spirals[i].x); + water[i].position.z = player.mesh.position.z + (WATER_TILE_SCALE * 2.0F * spirals[i].y); + } } for (int i = 0; i < OYSTERS_COUNT; i++) @@ -188,7 +202,7 @@ void Dolphin::onUpdate() float dist = vecDist.length(); if (dist < 20.F && player.isJumping() && oysters[i].isActive()) { - printf("Pickup %d Dist %d\n", i, dist); + printf("Pickup:%d Dist:%f\n", i, dist); oysters[i].disappear(); player.setLife(player.getLifes() + 1); engine->audio.setADPCMVolume(30, 3); @@ -204,11 +218,11 @@ void Dolphin::onUpdate() if (dist < 20.F && !mines[i].getExplosionTicks()) { - printf("Vecdist %f,%f,%f\n", vecDist.x, vecDist.y, vecDist.z); - printf("Explode %d Dist %d\n", i, dist); + printf("Vecdist: %f,%f,%f\n", vecDist.x, vecDist.y, vecDist.z); + printf("Explode:%d Dist:%f\n", i, dist); mines[i].explode(); player.setLife(player.getLifes() - 1); - //Buffer switching to prevent playing two sounds on one buffer + // Buffer switching to prevent playing two sounds on one buffer engine->audio.setADPCMVolume(65, Mine::lastSoundBuffer); engine->audio.playADPCM(boomSound, Mine::lastSoundBuffer); Mine::lastSoundBuffer = Mine::lastSoundBuffer == 4 ? 5 : 4; @@ -220,35 +234,34 @@ void Dolphin::onUpdate() player.update(engine->pad); camera.update(engine->pad, player.mesh); + skybox.position.set(player.mesh.position.x, +200.0F, player.mesh.position.z); waterbox.position.set(player.mesh.position.x, -260.0F, player.mesh.position.z); + engine->renderer->draw(island); - engine->renderer->draw(water); + engine->renderer->draw(waterDrawList, WATER_TILES_COUNT); engine->renderer->draw(skybox); engine->renderer->draw(waterbox); engine->renderer->draw(seabed); + for (u8 i = 0; i < OYSTERS_COUNT; i++) - { if (oysters[i].isActive()) - { engine->renderer->draw(oysters[i].mesh); - } - } + for (u8 i = 0; i < MINES_COUNT; i++) - { if (mines[i].getExplosionTicks() < MINE_EXPLOSION_TICKS) engine->renderer->draw(mines[i].mesh); - } + for (u8 i = 0; i < player.getLifes(); i++) - { engine->renderer->draw(lifeSprites[i]); - } + engine->renderer->draw(player.mesh); + if (camera.position.y < WATER_LEVEL) { engine->renderer->draw(waterOverlay); - engine->audio.setADPCMVolume(0, 0); //Surface ambient - engine->audio.setADPCMVolume(65, 1); //Underwater ambient + engine->audio.setADPCMVolume(0, 0); // Surface ambient + engine->audio.setADPCMVolume(65, 1); // Underwater ambient } else { @@ -256,3 +269,28 @@ void Dolphin::onUpdate() engine->audio.setADPCMVolume(0, 1); //Underwater ambient } } + +void Dolphin::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; + } +} diff --git a/src/samples/dolphin/dolphin.hpp b/src/samples/dolphin/dolphin.hpp index ad7b3c1..5ee4d05 100755 --- a/src/samples/dolphin/dolphin.hpp +++ b/src/samples/dolphin/dolphin.hpp @@ -37,8 +37,15 @@ public: static float engineFPS; private: - /*DO NOT TOUCH ORDER OF DECLARATION! - GCC BUG CAUSES RENDERING TO FAIL IN ANY OTHER ORDER OF DECLARATION!*/ + void calcSpiral(int X, int Y); + static const u16 WATER_TILES_COUNT = 1024; + + Point spirals[WATER_TILES_COUNT]; + Mesh **waterDrawList; + /** + * DO NOT TOUCH ORDER OF DECLARATION! + * GCC BUG CAUSES RENDERING TO FAIL IN ANY OTHER ORDER OF DECLARATION! + */ Mesh seabed; Mesh island; Mesh skybox; @@ -49,7 +56,7 @@ private: Collectible *oysters; TextureRepository *texRepo; Sprite waterOverlay; - Mesh water; + Mesh water[WATER_TILES_COUNT]; Mesh waterbox; Sprite lifeSprites[3]; Sprite gameOver; diff --git a/src/samples/dolphin/main.cpp b/src/samples/dolphin/main.cpp index d094a17..fdf11cb 100755 --- a/src/samples/dolphin/main.cpp +++ b/src/samples/dolphin/main.cpp @@ -18,4 +18,4 @@ int main() game.engine->init(&game, 128); SleepThread(); return 0; -} \ No newline at end of file +} diff --git a/src/samples/dolphin/objects/collectible.cpp b/src/samples/dolphin/objects/collectible.cpp index 9cd7d78..0bdd01c 100644 --- a/src/samples/dolphin/objects/collectible.cpp +++ b/src/samples/dolphin/objects/collectible.cpp @@ -25,10 +25,6 @@ Collectible::Collectible() bDisappearing = false; } -Collectible::~Collectible() -{ -} - void Collectible::disappear() { bDisappearing = true; diff --git a/src/samples/dolphin/objects/collectible.hpp b/src/samples/dolphin/objects/collectible.hpp index 32795ea..bac0b37 100644 --- a/src/samples/dolphin/objects/collectible.hpp +++ b/src/samples/dolphin/objects/collectible.hpp @@ -21,7 +21,6 @@ public: float rotation; Mesh mesh; Collectible(); - ~Collectible(); void update(); void disappear(); void setActive(const u8 &b) { bActive = b; } diff --git a/src/samples/dolphin/objects/mine.cpp b/src/samples/dolphin/objects/mine.cpp index 9a7a19b..a64da3a 100644 --- a/src/samples/dolphin/objects/mine.cpp +++ b/src/samples/dolphin/objects/mine.cpp @@ -20,10 +20,6 @@ Mine::Mine() explosionTicks = 0; } -Mine::~Mine() -{ -} - void Mine::update() { if (bExploding && explosionTicks < MINE_EXPLOSION_TICKS) diff --git a/src/samples/dolphin/objects/mine.hpp b/src/samples/dolphin/objects/mine.hpp index 5dce106..51faa71 100644 --- a/src/samples/dolphin/objects/mine.hpp +++ b/src/samples/dolphin/objects/mine.hpp @@ -24,7 +24,6 @@ public: void explode() { bExploding = true; } void update(); Mine(); - ~Mine(); const u8 &getExplosionTicks() { return explosionTicks; } private: diff --git a/src/samples/dolphin/objects/player.cpp b/src/samples/dolphin/objects/player.cpp index 84669cc..718f33a 100755 --- a/src/samples/dolphin/objects/player.cpp +++ b/src/samples/dolphin/objects/player.cpp @@ -28,10 +28,6 @@ Player::Player() lifes = 3; } -Player::~Player() -{ -} - void Player::init(Engine *t_engine) { pEngine = t_engine; @@ -63,8 +59,7 @@ void Player::update(Pad &t_pad) if (t_pad.isCrossClicked && mesh.getCurrentAnimationFrame() <= 14 && WATER_LEVEL - 15 < mesh.position.y) { - printf("Cross\n"); - mesh.setAnimSpeed(0.8F); + mesh.setAnimSpeed(1.0F); mesh.playAnimation(14, 58, 0); } @@ -72,19 +67,10 @@ void Player::update(Pad &t_pad) bIsJumping = true; else bIsJumping = false; - /* - if (lift < 0) - mesh.rotation.y = 1; - else if (lift > 0) - mesh.rotation.y = -1; - else - mesh.rotation.y = 0; - */ if (velocity > 0 && mesh.getCurrentAnimationFrame() == 0) { mesh.setAnimSpeed(0.05F); - printf("Swim animation\n"); mesh.playAnimation(1, 14, 0); } if (mesh.getCurrentAnimationFrame() == 42) @@ -101,7 +87,7 @@ void Player::update(Pad &t_pad) bIsImpactingWater = false; } - velocity *= 60.0F / Dolphin::engineFPS; //Moving by deltatime of last frame. + velocity *= 60.0F / Dolphin::engineFPS; // Moving by deltatime of last frame. mesh.position.z += Math::cos(mesh.rotation.z) * velocity * (bIsJumping + 1); mesh.position.x += diff --git a/src/samples/dolphin/objects/player.hpp b/src/samples/dolphin/objects/player.hpp index 3aed608..93cde51 100755 --- a/src/samples/dolphin/objects/player.hpp +++ b/src/samples/dolphin/objects/player.hpp @@ -25,7 +25,6 @@ public: float gravity, velocity, lift; Mesh mesh; Player(); - ~Player(); void init(Engine *t_engine); void update(Pad &t_pad); const u8 &isJumping() { return bIsJumping; } diff --git a/src/samples/floors/README.MD b/src/samples/floors/README.MD index 7f8391d..30d0602 100644 --- a/src/samples/floors/README.MD +++ b/src/samples/floors/README.MD @@ -1,14 +1,19 @@ ## Floors sample -### Description - -Simple demo which shows lighting using PATH3, and player movement and animation. +### Features +- Box collision +- 2 animated characters +- Texture tricks showcase +- Background song +- Audio effects - walking, fighting (ADPCM) +- Transparent 2D UI +- Usage of draw() in array mode (for floors, very fast) ### Assets -[Download](http://apgcglz.cluster028.hosting.ovh.net/tyra/1.1.0/samples/floors/assets.zip) +[Download](http://apgcglz.cluster028.hosting.ovh.net/tyra/1.31.2/samples/floors/assets.zip) ### Screenshot [![Floors screenshot][floors-screenshot]](#) -[floors-screenshot]: http://apgcglz.cluster028.hosting.ovh.net/tyra/1.1.0/samples/floors/floors.gif +[floors-screenshot]: http://apgcglz.cluster028.hosting.ovh.net/tyra/1.31.2/samples/floors/floors.gif diff --git a/src/samples/floors/camera.cpp b/src/samples/floors/camera.cpp index 56c4aa1..e797c0f 100644 --- a/src/samples/floors/camera.cpp +++ b/src/samples/floors/camera.cpp @@ -19,13 +19,10 @@ const float CAMERA_Y = 30.0F; // Constructors/Destructors // ---- -Camera::Camera(ScreenSettings *t_screen) : CameraBase(t_screen, &position, &up) +Camera::Camera(ScreenSettings *t_screen) : CameraBase(t_screen, &position) { PRINT_LOG("Initializing camera"); verticalLevel = 80.0F; - up.x = 0.0F; - up.y = 1.0F; - up.z = 0.0F; PRINT_LOG("Camera initialized!"); } diff --git a/src/samples/floors/camera.hpp b/src/samples/floors/camera.hpp index 4d6adf8..49735d2 100644 --- a/src/samples/floors/camera.hpp +++ b/src/samples/floors/camera.hpp @@ -35,7 +35,6 @@ public: protected: Vector3 *getPosition() { return &position; }; - Vector3 *getUp() { return &up; }; ScreenSettings screen; }; diff --git a/src/samples/floors/floors.cpp b/src/samples/floors/floors.cpp index 2a55ab1..330c68a 100644 --- a/src/samples/floors/floors.cpp +++ b/src/samples/floors/floors.cpp @@ -37,17 +37,17 @@ Floors::~Floors() void Floors::onInit() { + texRepo = engine->renderer->getTextureRepository(); + enemy = new Enemy(texRepo); + ui = new Ui(texRepo); + floorManager = new FloorManager(FLOORS_COUNT, texRepo); // we must init FloorManager before starting audio! + player = new Player(&engine->audio, texRepo); setBgColorAndAmbientColor(); - engine->renderer->setCameraDefinitions(&camera.worldView, &camera.unitCirclePosition, camera.planes); + engine->renderer->setCameraDefinitions(&camera.view, &camera.unitCirclePosition, camera.planes); engine->audio.addSongListener(this); engine->audio.loadSong("sounds/mafikizolo-loot.wav"); engine->audio.playSong(); engine->audio.setSongVolume(80); - texRepo = engine->renderer->getTextureRepository(); - enemy = new Enemy(texRepo); - ui = new Ui(texRepo); - floorManager = new FloorManager(FLOORS_COUNT, texRepo); - player = new Player(&engine->audio, texRepo); } void Floors::onUpdate() @@ -60,8 +60,11 @@ void Floors::onUpdate() player->update(engine->pad, camera, *floorManager, *enemy); engine->renderer->draw(player->mesh); engine->renderer->draw(enemy->getMeshes(), enemy->getMeshesCount()); - for (u16 i = 0; i < FLOORS_COUNT; i++) - engine->renderer->drawByPath3(floorManager->floors[i].mesh, lightManager.bulbs, lightManager.bulbsCount); + + // You can draw array of meshes in draw() function also. It can be A LOT faster than for looping! + // Why? When given mesh is small, is not animated and is not backface culled, vertex data are send once! + engine->renderer->draw(floorManager->getMeshes(), FLOORS_COUNT, lightManager.bulbs, lightManager.bulbsCount); + ui->render(engine->renderer); // 2D rendering ist LAST step, because layers gonna play there. } diff --git a/src/samples/floors/managers/floor_manager.cpp b/src/samples/floors/managers/floor_manager.cpp index e1b1d09..cc2e0ae 100644 --- a/src/samples/floors/managers/floor_manager.cpp +++ b/src/samples/floors/managers/floor_manager.cpp @@ -12,6 +12,7 @@ #include #include +#include // ---- // Constructors/Destructors @@ -22,17 +23,17 @@ */ FloorManager::FloorManager(int t_floorAmount, TextureRepository *t_texRepo) { + meshes = new Mesh *[t_floorAmount]; texRepo = t_texRepo; floorAmount = t_floorAmount; spirals = new Point[t_floorAmount]; - int floorSpiralMaxOffset = (int)Math::sqrt(t_floorAmount); + int floorSpiralMaxOffset = (int)sqrt(t_floorAmount); calcSpiral(floorSpiralMaxOffset, floorSpiralMaxOffset); initFloors(); trick = 0.0F; - trickMode = 0; isTimeForChangeTriggerColor = true; isTimeForChangeDefaultColor = true; - audioOffset = audioMode = audioTick = 0; + audioOffset = audioMode = audioTick = trickMode = 0; } FloorManager::~FloorManager() @@ -85,12 +86,14 @@ void FloorManager::initFloors() floors[0].mesh.loadObj("meshes/floor/", "floor", 3.0F, false); floors[0].mesh.shouldBeFrustumCulled = true; floors[0].mesh.shouldBeLighted = true; + meshes[0] = &floors[0].mesh; texRepo->addByMesh("meshes/floor/", floors[0].mesh, BMP); for (u16 i = 1; i < floorAmount; i++) { + floors[i].mesh.shouldBeFrustumCulled = true; floors[i].init(floors[0].mesh, spirals[i], i); - texRepo->getByMesh(floors[0].mesh.getId(), floors[0].mesh.getMaterial(0).getId()) - ->addLink(floors[i].mesh.getId(), floors[i].mesh.getMaterial(0).getId()); + texRepo->getBySpriteOrMesh(floors[0].mesh.getMaterial(0).getId())->addLink(floors[i].mesh.getMaterial(0).getId()); + meshes[i] = &floors[i].mesh; } PRINT_LOG("Floors initialized!"); } @@ -120,18 +123,18 @@ void FloorManager::update(Player &t_player) for (u16 i = 0; i < floorAmount; i++) { floors[i].animate(t_player); - + MeshMaterial *material = &floors[i].mesh.getMaterial(0); if (floors[i].isByAudioTriggered) { - floors[i].mesh.color.r = trigColor.r; - floors[i].mesh.color.g = trigColor.g; - floors[i].mesh.color.b = trigColor.b; + material->color.r = trigColor.r; + material->color.g = trigColor.g; + material->color.b = trigColor.b; } else { - floors[i].mesh.color.r = defaultColor.r; - floors[i].mesh.color.g = defaultColor.g; - floors[i].mesh.color.b = defaultColor.b; + material->color.r = defaultColor.r; + material->color.g = defaultColor.g; + material->color.b = defaultColor.b; } } } diff --git a/src/samples/floors/managers/floor_manager.hpp b/src/samples/floors/managers/floor_manager.hpp index 61a64b7..342aefd 100644 --- a/src/samples/floors/managers/floor_manager.hpp +++ b/src/samples/floors/managers/floor_manager.hpp @@ -31,8 +31,10 @@ public: u16 floorAmount; void update(Player &t_player); void onAudioTick(); + Mesh **getMeshes() { return meshes; } private: + Mesh **meshes; TextureRepository *texRepo; u8 audioOffset, audioMode; u32 audioTick; diff --git a/src/samples/floors/objects/enemy.cpp b/src/samples/floors/objects/enemy.cpp index 858e79c..2e8aa42 100644 --- a/src/samples/floors/objects/enemy.cpp +++ b/src/samples/floors/objects/enemy.cpp @@ -16,6 +16,7 @@ #include #include #include +#include // ---- // Constructors/Destructors @@ -26,30 +27,25 @@ Enemy::Enemy(TextureRepository *t_texRepo) PRINT_LOG("Creating enemy object"); meshes = new Mesh[getMeshesCount()]; + drawMeshes = new Mesh *[getMeshesCount()]; meshes[0].loadMD2("meshes/enemy/", "poss_head", 0.3F, false); - meshes[0].rotation.x = -1.566F; - meshes[0].rotation.z = 1.566F; - meshes[1].loadMD2("meshes/enemy/", "poss_body", 0.3F, false); - meshes[1].rotation.x = -1.566F; - meshes[1].rotation.z = 1.566F; - meshes[2].loadMD2("meshes/enemy/", "poss_weapon", 0.3F, false); - meshes[2].rotation.x = -1.566F; - meshes[2].rotation.z = 1.566F; + + for (u8 i = 0; i < 3; i++) + { + meshes[i].rotation.x = -1.566F; + meshes[i].rotation.z = 1.566F; + meshes[i].shouldBeFrustumCulled = false; + t_texRepo->addByMesh("meshes/enemy/", meshes[i], PNG); + meshes[i].playAnimation(1, 6); + drawMeshes[i] = &meshes[i]; + } Vector3 initPos = Vector3(0.00F, 40.00F, 0.00F); setPosition(initPos); - t_texRepo->addByMesh("meshes/enemy/", meshes[0], PNG); - t_texRepo->addByMesh("meshes/enemy/", meshes[1], PNG); - t_texRepo->addByMesh("meshes/enemy/", meshes[2], PNG); - - meshes[0].playAnimation(1, 6); - meshes[1].playAnimation(1, 6); - meshes[2].playAnimation(1, 6); - isKilled = true; PRINT_LOG("Enemy object created!"); diff --git a/src/samples/floors/objects/enemy.hpp b/src/samples/floors/objects/enemy.hpp index 601a4e9..4ed530a 100644 --- a/src/samples/floors/objects/enemy.hpp +++ b/src/samples/floors/objects/enemy.hpp @@ -24,7 +24,7 @@ public: Enemy(TextureRepository *t_texRepo); ~Enemy(); - inline Mesh *getMeshes() const { return meshes; } + inline Mesh **getMeshes() const { return drawMeshes; } inline u8 getMeshesCount() const { return 3; } inline Vector3 getPosition() const { return position; } void setPosition(const Vector3 &t_vec); @@ -35,6 +35,8 @@ public: private: /** 0 - head, 1 - body, 2 - weapon */ Mesh *meshes; + /** Only for draw() method. */ + Mesh **drawMeshes; const Floor *currentFloor; Vector3 position, currFloorMin, currFloorMax; u8 isKilled; diff --git a/src/samples/floors/objects/player.cpp b/src/samples/floors/objects/player.cpp index 6d6ae79..738d03a 100644 --- a/src/samples/floors/objects/player.cpp +++ b/src/samples/floors/objects/player.cpp @@ -211,13 +211,13 @@ FloorsCheck *Player::checkFloors(const FloorManager &t_floorManager, const Vecto for (u32 i = 0; i < t_floorManager.floorAmount; i++) { Utils::getMinMax(t_floorManager.floors[i].mesh, min, max); - if (result->currentFloor == NULL && this->mesh.position.isOnSquare(min, max)) + if (result->currentFloor == NULL && this->mesh.position.isOnBox(min, max)) { result->currentFloor = &t_floorManager.floors[i]; result->currFloorMin.set(min); result->currFloorMax.set(max); } - if (result->willCollideFloor == NULL && t_nextPos.collidesSquare(min, max)) + if (result->willCollideFloor == NULL && t_nextPos.collidesBox(min, max)) { result->willCollideFloor = &t_floorManager.floors[i]; result->willCollideFloorMin.set(min); diff --git a/src/samples/floors/ui.cpp b/src/samples/floors/ui.cpp index 52c43ff..d398cd9 100644 --- a/src/samples/floors/ui.cpp +++ b/src/samples/floors/ui.cpp @@ -66,13 +66,13 @@ void Ui::update(const Player &player) if (!isTask1Done && player.getJumpCount() >= 10) { isTask1Done = true; - grayCheckboxTex->removeLinkBySprite(task1Checkbox.getId()); + grayCheckboxTex->removeLinkById(task1Checkbox.getId()); blueCheckboxTex->addLink(task1Checkbox.getId()); } if (!isTask2Done && player.getKilledEnemiesCount() >= 10) { isTask2Done = true; - grayCheckboxTex->removeLinkBySprite(task2Checkbox.getId()); + grayCheckboxTex->removeLinkById(task2Checkbox.getId()); blueCheckboxTex->addLink(task2Checkbox.getId()); } }