tyrav2 init

This commit is contained in:
h4570
2022-07-17 10:21:35 +02:00
parent 44c1ee4fe8
commit c8b22ff331
249 changed files with 18187 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2020, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/bbox/bbox.hpp"
namespace Tyra {
BBox::BBox(CoreBBox** t_bboxes, const u32& count) : CoreBBox(t_bboxes, count) {
setData();
}
BBox::BBox(Vec4* t_vertices, u32 count) : CoreBBox(t_vertices, count) {
setData();
}
BBox::BBox(Vec4* t_vertices, u32* faces, u32 count)
: CoreBBox(t_vertices, faces, count) {
setData();
}
BBox::BBox(Vec4* t_vertices) : CoreBBox(t_vertices) { setData(); }
void BBox::setData() {
// This might be shortened with Vec4 operator overloading, but current
// implementation is more human readable.
_height = _vertices[0].y - _vertices[2].y;
_width = _vertices[0].x - _vertices[4].x;
_depth = _vertices[0].z - _vertices[1].z;
_centerVector = _vertices[0];
_centerVector.x += (_width / 2);
_centerVector.y += (_height / 2);
_centerVector.z += (_depth / 2);
// Z-Axis faces
_frontFace = BBoxFace(_vertices[1], _vertices[7], _vertices[1].z);
_backFace = BBoxFace(_vertices[0], _vertices[6], _vertices[0].z);
// X-Axis faces
_leftFace = BBoxFace(_vertices[0], _vertices[3], _vertices[0].x);
_rightFace = BBoxFace(_vertices[4], _vertices[7], _vertices[4].x);
// Y-Axis faces
_topFace = BBoxFace(_vertices[2], _vertices[7], _vertices[2].y);
_bottomFace = BBoxFace(_vertices[0], _vertices[5], _vertices[0].y);
}
} // namespace Tyra
+144
View File
@@ -0,0 +1,144 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2020, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include <tamtypes.h>
#include "math/m4x4.hpp"
#include "renderer/3d/mesh/mesh.hpp"
namespace Tyra {
Mesh::Mesh(const MeshBuilderData& data) {
id = rand() % 1000000;
framesCount = data.framesCount;
TYRA_ASSERT(framesCount > 0, "Frames count must be greater than 0");
materialsCount = data.materialsCount;
TYRA_ASSERT(materialsCount > 0, "Materials count must be greater than 0");
frames = new MeshFrame*[framesCount];
for (u32 i = 0; i < framesCount; i++) {
frames[i] = new MeshFrame(data, i);
}
materials = new MeshMaterial*[materialsCount];
for (u32 i = 0; i < materialsCount; i++) {
materials[i] = new MeshMaterial(data, i);
}
translation.translate(Vec4(0.0F, 0.0F, 0.0F, 1.0F));
initMesh();
_isMother = true;
}
Mesh::Mesh(const Mesh& mesh) {
id = rand() % 1000000;
framesCount = mesh.framesCount;
materialsCount = mesh.materialsCount;
frames = new MeshFrame*[framesCount];
for (u32 i = 0; i < framesCount; i++) {
frames[i] = new MeshFrame(*mesh.frames[i]);
}
materials = new MeshMaterial*[materialsCount];
for (u32 i = 0; i < materialsCount; i++) {
materials[i] = new MeshMaterial(*mesh.materials[i]);
}
translation.translate(Vec4(0.0F, 0.0F, 0.0F, 1.0F));
initMesh();
_isMother = false;
}
Mesh::~Mesh() {
for (u32 i = 0; i < framesCount; i++) {
delete frames[i];
}
delete[] frames;
for (u32 i = 0; i < materialsCount; i++) {
delete materials[i];
delete[] materials;
}
}
M4x4 Mesh::getModelMatrix() const { return translation * rotation * scale; }
void Mesh::initMesh() {
animState.startFrame = 0;
animState.endFrame = 0;
animState.interpolation = 0.0F;
animState.animType = 0;
animState.currentFrame = 0;
animState.stayFrame = 0;
animState.isStayFrameSet = false;
animState.nextFrame = 0;
animState.speed = 0.1F;
}
void Mesh::playAnimation(const u32& t_startFrame, const u32& t_endFrame) {
TYRA_ASSERT(framesCount > 0,
"Cant play animation, because no mesh data was loaded!");
TYRA_ASSERT(framesCount != 1,
"Cant play animation, because this mesh have only one frame.");
TYRA_ASSERT(
t_endFrame < framesCount,
"End frame value is too high. Valid range: (0, getFramesCount()-1)");
animState.startFrame = t_startFrame;
animState.endFrame = t_endFrame;
if (animState.currentFrame == t_startFrame)
animState.nextFrame = t_endFrame;
else
animState.nextFrame = t_startFrame;
}
void Mesh::playAnimation(const u32& t_startFrame, const u32& t_endFrame,
const u32& t_stayFrame) {
TYRA_ASSERT(framesCount > 0,
"Cant play animation, because no mesh data was loaded!");
TYRA_ASSERT(framesCount != 1,
"Cant play animation, because this mesh have only one frame.");
TYRA_ASSERT(
t_endFrame < framesCount,
"End frame value is too high. Valid range: (0, getFramesCount()-1)");
animState.startFrame = t_startFrame;
animState.endFrame = t_endFrame;
animState.isStayFrameSet = true;
animState.stayFrame = t_stayFrame;
animState.nextFrame = t_startFrame;
}
void Mesh::animate() {
animState.interpolation += animState.speed;
if (animState.interpolation >= 1.0F) {
animState.interpolation = 0.0F;
animState.currentFrame = animState.nextFrame;
if (++animState.nextFrame > animState.endFrame) {
if (animState.isStayFrameSet) {
animState.isStayFrameSet = false;
animState.nextFrame = animState.stayFrame;
animState.startFrame = animState.stayFrame;
animState.endFrame = animState.stayFrame;
} else {
animState.nextFrame = animState.startFrame;
}
}
}
}
} // namespace Tyra
+150
View File
@@ -0,0 +1,150 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2020, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "debug/debug.hpp"
#include <tamtypes.h>
#include <string>
#include "math/vec4.hpp"
#include "renderer/models/color.hpp"
#include "renderer/3d/mesh/mesh_frame.hpp"
namespace Tyra {
MeshFrame::MeshFrame(const MeshBuilderData& data, const u32& index) {
TYRA_ASSERT(index < data.framesCount && index >= 0, "Provided index \"",
index, "\" is out of range");
id = rand() % 1000000;
vertices = data.frames[index]->vertices;
TYRA_ASSERT(vertices != nullptr, "Vertices are required");
vertexCount = data.frames[index]->verticesCount;
TYRA_ASSERT(vertexCount > 0, "Vertices count must be greater than 0");
if (data.normalsEnabled) {
normals = data.frames[index]->normals;
normalsCount = data.frames[index]->normalsCount;
TYRA_ASSERT(normals != nullptr, "Normals are required");
} else {
normalsCount = 0;
normals = nullptr;
}
if (data.textureCoordsEnabled) {
textureCoords = data.frames[index]->textureCoords;
textureCoordsCount = data.frames[index]->textureCoordsCount;
TYRA_ASSERT(textureCoords != nullptr, "Texture coordinates are required");
} else {
textureCoordsCount = 0;
textureCoords = nullptr;
}
if (data.manyColorsEnabled) {
colors = data.frames[index]->colors;
colorsCount = data.frames[index]->colorsCount;
TYRA_ASSERT(colors != nullptr, "Colors are required");
} else {
colorsCount = 0;
colors = nullptr;
}
bbox =
new BBox(data.frames[index]->vertices, data.frames[index]->verticesCount);
_isMother = true;
}
MeshFrame::MeshFrame(const MeshFrame& frame) {
id = rand() % 1000000;
vertices = frame.vertices;
normals = frame.normals;
textureCoords = frame.textureCoords;
colors = frame.colors;
vertexCount = frame.vertexCount;
normalsCount = frame.normalsCount;
textureCoordsCount = frame.textureCoordsCount;
colorsCount = frame.colorsCount;
bbox = frame.bbox;
_isMother = false;
}
MeshFrame::~MeshFrame() {
if (_isMother) {
delete[] vertices;
if (normals) delete[] normals;
if (textureCoords) delete[] textureCoords;
if (colors) delete[] colors;
delete bbox;
}
}
void MeshFrame::print() const {
auto text = getPrint(nullptr);
printf("%s\n", text.c_str());
}
void MeshFrame::print(const char* name) const {
auto text = getPrint(name);
printf("%s\n", text.c_str());
}
std::string MeshFrame::getPrint(const char* name) const {
std::stringstream res;
if (name) {
res << name << "(";
} else {
res << "MeshFrame(";
}
res << std::fixed << std::setprecision(2);
res << "Id: " << id << ", " << std::endl;
res << "VertexCount: " << vertexCount << ", " << std::endl;
res << "NormalsCount: " << normalsCount << ", " << std::endl;
res << "TextureCoordsCount: " << textureCoordsCount << ", " << std::endl;
res << "ColorsCount: " << colorsCount << ", " << std::endl;
res << "BBox: " << bbox->getPrint() << ", " << std::endl;
res << "Vertices: ";
for (u32 i = 0; i < vertexCount; i++) {
res << vertices[i].getPrint() << ", " << std::endl;
}
if (normals) {
res << "Normals: ";
for (u32 i = 0; i < normalsCount; i++) {
res << normals[i].getPrint() << ", " << std::endl;
}
}
if (textureCoords) {
res << "TextureCoords: ";
for (u32 i = 0; i < textureCoordsCount; i++) {
res << textureCoords[i].getPrint() << ", " << std::endl;
}
}
if (colors) {
res << "Colors: ";
for (u32 i = 0; i < colorsCount; i++) {
res << colors[i].getPrint() << ", " << std::endl;
}
}
res << ")";
return res.str();
}
} // namespace Tyra
@@ -0,0 +1,179 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2020, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include <tamtypes.h>
#include <string>
#include <cstdlib>
#include "renderer/3d/mesh/mesh_material.hpp"
namespace Tyra {
MeshMaterial::MeshMaterial(const MeshBuilderData& data,
const u32& materialIndex)
: singleColor(false) {
TYRA_ASSERT(materialIndex < data.materialsCount && materialIndex >= 0,
"Provided index \"", materialIndex, "\" is out of range");
id = rand() % 1000000;
vertexFaces = data.materials[materialIndex]->vertexFaces;
TYRA_ASSERT(vertexFaces != nullptr, "Vertex faces are required");
if (data.textureCoordsEnabled) {
textureCoordFaces = data.materials[materialIndex]->textureCoordFaces;
TYRA_ASSERT(textureCoordFaces != nullptr,
"Texture coord faces are required");
} else {
textureCoordFaces = nullptr;
}
if (data.normalsEnabled) {
normalFaces = data.materials[materialIndex]->normalFaces;
TYRA_ASSERT(normalFaces != nullptr, "Normal faces are required");
} else {
normalFaces = nullptr;
}
if (data.manyColorsEnabled) {
colorFaces = data.materials[materialIndex]->colorFaces;
singleColorFlag = false;
TYRA_ASSERT(colorFaces != nullptr, "Colors faces are required");
} else {
colorFaces = nullptr;
singleColorFlag = true;
}
singleColor.set(128.0F, 128.0F, 128.0F, 128.0F);
facesCount = data.materials[materialIndex]->count;
TYRA_ASSERT(facesCount > 0, "Faces count must be greater than 0");
_name = data.materials[materialIndex]->name;
TYRA_ASSERT(_name.length() > 0, "MeshMaterial name cannot be empty");
framesCount = data.framesCount;
frames = new MeshMaterialFrame*[framesCount];
for (u32 i = 0; i < framesCount; i++) {
frames[i] = new MeshMaterialFrame(data, i, materialIndex);
}
_isMother = true;
}
MeshMaterial::MeshMaterial(const MeshMaterial& mesh) {
id = rand() % 1000000;
vertexFaces = mesh.vertexFaces;
textureCoordFaces = mesh.textureCoordFaces;
normalFaces = mesh.normalFaces;
colorFaces = mesh.colorFaces;
facesCount = mesh.facesCount;
framesCount = mesh.framesCount;
_name = mesh._name;
singleColor.set(128.0F, 128.0F, 128.0F, 128.0F);
frames = new MeshMaterialFrame*[framesCount];
for (u32 i = 0; i < framesCount; i++) {
frames[i] = new MeshMaterialFrame(*mesh.frames[i]);
}
_isMother = false;
}
MeshMaterial::~MeshMaterial() {
if (_isMother) {
delete[] vertexFaces;
if (textureCoordFaces) delete[] textureCoordFaces;
if (normalFaces) delete[] normalFaces;
if (colorFaces) delete[] colorFaces;
}
for (u32 i = 0; i < framesCount; i++) {
delete frames[i];
}
delete[] frames;
}
const BBox& MeshMaterial::getBBox(const u32& frame) const {
return frames[frame]->getBBox();
}
void MeshMaterial::setSingleColorFlag(const u8& flag) {
TYRA_ASSERT(
colorFaces != nullptr,
"Colors and color faces are required to use color-per-vertex mode");
singleColorFlag = flag;
}
void MeshMaterial::print() const {
auto text = getPrint(nullptr);
printf("%s\n", text.c_str());
}
void MeshMaterial::print(const char* name) const {
auto text = getPrint(name);
printf("%s\n", text.c_str());
}
std::string MeshMaterial::getPrint(const char* name) const {
std::stringstream res;
if (name) {
res << name << "(";
} else {
res << "MeshMaterial(";
}
res << std::endl;
res << std::fixed << std::setprecision(2);
res << "Id: " << id << ", " << std::endl;
res << "Name: " << _name << ", " << std::endl;
res << "FacesCount: " << facesCount << ", " << std::endl;
res << "FramesCount: " << framesCount << ", " << std::endl;
res << "vertexFaces: " << std::endl;
for (u32 i = 0; i < facesCount; i++) {
res << vertexFaces[i] << ", ";
if (i % 3 == 2) res << std::endl;
}
if (textureCoordFaces) {
res << "TextureCoordFaces: " << std::endl;
for (u32 i = 0; i < facesCount; i++) {
res << textureCoordFaces[i] << ", ";
if (i % 3 == 2) res << std::endl;
}
}
if (normalFaces) {
res << "NormalFaces: " << std::endl;
for (u32 i = 0; i < facesCount; i++) {
res << normalFaces[i] << ", ";
if (i % 3 == 2) res << std::endl;
}
}
if (colorFaces) {
res << "ColorFaces: " << std::endl;
for (u32 i = 0; i < facesCount; i++) {
res << colorFaces[i] << ", ";
if (i % 3 == 2) res << std::endl;
}
}
res << ")";
return res.str();
}
} // namespace Tyra
@@ -0,0 +1,51 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2020, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "debug/debug.hpp"
#include <tamtypes.h>
#include "renderer/models/color.hpp"
#include "loaders/3d/builder/mesh_builder_data.hpp"
#include "renderer/3d/mesh/mesh_material_frame.hpp"
namespace Tyra {
MeshMaterialFrame::MeshMaterialFrame(const MeshBuilderData& data,
const u32& frameIndex,
const u32& materialIndex) {
TYRA_ASSERT(frameIndex < data.framesCount && frameIndex >= 0,
"Provided index \"", frameIndex, "\" is out of range");
TYRA_ASSERT(materialIndex < data.materialsCount && materialIndex >= 0,
"Provided index \"", materialIndex, "\" is out of range");
id = rand() % 1000000;
bbox = new BBox(data.frames[frameIndex]->vertices,
data.materials[materialIndex]->vertexFaces,
data.materials[materialIndex]->count);
_isMother = true;
}
MeshMaterialFrame::MeshMaterialFrame(const MeshMaterialFrame& frame) {
id = rand() % 1000000;
bbox = frame.bbox;
_isMother = false;
}
MeshMaterialFrame::~MeshMaterialFrame() {
if (_isMother) {
delete bbox;
}
}
} // namespace Tyra
@@ -0,0 +1,25 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/minecraft/data/mcpip_block_data.hpp"
namespace Tyra {
McpipBlockData::McpipBlockData() {
vertices = nullptr;
textureCoords = nullptr;
comboData = nullptr;
offset = 0.0F;
count = 0;
}
McpipBlockData::~McpipBlockData() {}
} // namespace Tyra
@@ -0,0 +1,132 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0F
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/minecraft/data/mcpip_multi_tex_block_data.hpp"
namespace Tyra {
McpipMultiTexBlockData::McpipMultiTexBlockData() {
allocateTempData();
unroll();
dellocateTempData();
}
McpipMultiTexBlockData::~McpipMultiTexBlockData() {
if (comboData != nullptr) {
delete[] comboData;
}
}
void McpipMultiTexBlockData::allocateTempData() {
u32 tempVertsStsCount = 24;
tempVerts = new Tyra::Vec4[tempVertsStsCount];
tempVerts[0].set(-1.0F, -1.0F, -1.0F);
tempVerts[1].set(1.0F, -1.0F, -1.0F);
tempVerts[2].set(1.0F, -1.0F, 1.0F);
tempVerts[3].set(-1.0F, -1.0F, 1.0F);
tempVerts[4].set(1.0F, -1.0F, 1.0F);
tempVerts[5].set(1.0F, 1.0F, 1.0F);
tempVerts[6].set(-1.0F, 1.0F, 1.0F);
tempVerts[7].set(-1.0F, -1.0F, 1.0F);
tempVerts[8].set(-1.0F, -1.0F, 1.0F);
tempVerts[9].set(-1.0F, 1.0F, 1.0F);
tempVerts[10].set(-1.0F, 1.0F, -1.0F);
tempVerts[11].set(-1.0F, -1.0F, -1.0F);
tempVerts[12].set(1.0F, -1.0F, -1.0F);
tempVerts[13].set(1.0F, 1.0F, -1.0F);
tempVerts[14].set(1.0F, 1.0F, 1.0F);
tempVerts[15].set(1.0F, -1.0F, 1.0F);
tempVerts[16].set(-1.0F, -1.0F, -1.0F);
tempVerts[17].set(-1.0F, 1.0F, -1.0F);
tempVerts[18].set(1.0F, 1.0F, -1.0F);
tempVerts[19].set(1.0F, -1.0F, -1.0F);
tempVerts[20].set(1.0F, 1.0F, -1.0F);
tempVerts[21].set(-1.0F, 1.0F, -1.0F);
tempVerts[22].set(-1.0F, 1.0F, 1.0F);
tempVerts[23].set(1.0F, 1.0F, 1.0F);
tempTexCoords = new Tyra::Vec4[tempVertsStsCount];
tempTexCoords[0].set(0.062721F, 0.813282F, 1.0F, 0.0F);
tempTexCoords[1].set(0.062721F, 0.875327F, 1.0F, 0.0F);
tempTexCoords[2].set(0.000676F, 0.875327F, 1.0F, 0.0F);
tempTexCoords[3].set(0.000676F, 0.813282F, 1.0F, 0.0F);
tempTexCoords[4].set(0.062095F, 0.750461F, 1.0F, 0.0F);
tempTexCoords[5].set(0.062095F, 0.812244F, 1.0F, 0.0F);
tempTexCoords[6].set(0.000311F, 0.812244F, 1.0F, 0.0F);
tempTexCoords[7].set(0.000311F, 0.750461F, 1.0F, 0.0F);
tempTexCoords[8].set(0.062629F, 0.687779F, 1.0F, 0.0F);
tempTexCoords[9].set(0.000000F, 0.687779F, 1.0F, 0.0F);
tempTexCoords[10].set(0.000000F, 0.624816F, 1.0F, 0.0F);
tempTexCoords[11].set(0.062629F, 0.624816F, 1.0F, 0.0F);
tempTexCoords[12].set(0.062667F, 0.626382F, 1.0F, 0.0F);
tempTexCoords[13].set(0.000000F, 0.626382F, 1.0F, 0.0F);
tempTexCoords[14].set(0.000000F, 0.561642F, 1.0F, 0.0F);
tempTexCoords[15].set(0.062667F, 0.561642F, 1.0F, 0.0F);
tempTexCoords[16].set(0.000000F, 0.937621F, 1.0F, 0.0F);
tempTexCoords[17].set(0.000000F, 0.875134F, 1.0F, 0.0F);
tempTexCoords[18].set(0.062128F, 0.875134F, 1.0F, 0.0F);
tempTexCoords[19].set(0.062128F, 0.937621F, 1.0F, 0.0F);
tempTexCoords[20].set(0.000000F, 0.937223F, 1.0F, 0.0F);
tempTexCoords[21].set(0.062223F, 0.937223F, 1.0F, 0.0F);
tempTexCoords[22].set(0.062223F, 0.999641F, 1.0F, 0.0F);
tempTexCoords[23].set(0.000000F, 0.999641F, 1.0F, 0.0F);
// Because 16 blocks can fit in single column of 256x256 tex atlas
offset = 1.0F / 16.0F;
for (u32 i = 0; i < tempVertsStsCount; i++)
tempTexCoords[i].y = 1.0F - tempTexCoords[i].y;
tempVertFaces = new u32[36];
tempTexCoordsFaces = new u32[36];
std::string vertexFaces =
"1,2,3,1,3,4,5,6,7,5,7,8,9,10,11,9,11,12,13,14,15,13,15,16,17,18,19,17,"
"19,20,21,22,23,21,23,24";
std::stringstream ssVertexFaces(vertexFaces);
std::string texCoordFaces =
"1,2,3,1,3,4,5,6,7,5,7,8,9,10,11,9,11,12,13,14,15,13,15,16,17,18,19,17,"
"19,20,21,22,23,21,23,24";
std::stringstream ssTexCoordFaces(texCoordFaces);
int i = 0;
std::string item;
while (std::getline(ssVertexFaces, item, ','))
tempVertFaces[i++] = std::stoi(item) - 1;
i = 0;
while (std::getline(ssTexCoordFaces, item, ','))
tempTexCoordsFaces[i++] = std::stoi(item) - 1;
}
void McpipMultiTexBlockData::unroll() {
count = 36;
comboData = new Tyra::Vec4[36 * 2];
vertices = &comboData[0];
textureCoords = &comboData[36];
for (u32 i = 0; i < count; i++) {
vertices[i] = tempVerts[tempVertFaces[i]];
textureCoords[i] = tempTexCoords[tempTexCoordsFaces[i]];
}
}
void McpipMultiTexBlockData::dellocateTempData() {
delete[] tempVerts;
delete[] tempTexCoords;
delete[] tempVertFaces;
delete[] tempTexCoordsFaces;
}
} // namespace Tyra
@@ -0,0 +1,132 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0F
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/minecraft/data/mcpip_single_tex_block_data.hpp"
namespace Tyra {
McpipSingleTexBlockData::McpipSingleTexBlockData() {
allocateTempData();
unroll();
dellocateTempData();
}
McpipSingleTexBlockData::~McpipSingleTexBlockData() {
if (comboData != nullptr) {
delete[] comboData;
}
}
void McpipSingleTexBlockData::allocateTempData() {
u32 tempVertsStsCount = 24;
tempVerts = new Tyra::Vec4[tempVertsStsCount];
tempVerts[0].set(-1.0F, -1.0F, -1.0F);
tempVerts[1].set(1.0F, -1.0F, -1.0F);
tempVerts[2].set(1.0F, -1.0F, 1.0F);
tempVerts[3].set(-1.0F, -1.0F, 1.0F);
tempVerts[4].set(1.0F, -1.0F, 1.0F);
tempVerts[5].set(1.0F, 1.0F, 1.0F);
tempVerts[6].set(-1.0F, 1.0F, 1.0F);
tempVerts[7].set(-1.0F, -1.0F, 1.0F);
tempVerts[8].set(-1.0F, -1.0F, 1.0F);
tempVerts[9].set(-1.0F, 1.0F, 1.0F);
tempVerts[10].set(-1.0F, 1.0F, -1.0F);
tempVerts[11].set(-1.0F, -1.0F, -1.0F);
tempVerts[12].set(1.0F, -1.0F, -1.0F);
tempVerts[13].set(1.0F, 1.0F, -1.0F);
tempVerts[14].set(1.0F, 1.0F, 1.0F);
tempVerts[15].set(1.0F, -1.0F, 1.0F);
tempVerts[16].set(-1.0F, -1.0F, -1.0F);
tempVerts[17].set(-1.0F, 1.0F, -1.0F);
tempVerts[18].set(1.0F, 1.0F, -1.0F);
tempVerts[19].set(1.0F, -1.0F, -1.0F);
tempVerts[20].set(1.0F, 1.0F, -1.0F);
tempVerts[21].set(-1.0F, 1.0F, -1.0F);
tempVerts[22].set(-1.0F, 1.0F, 1.0F);
tempVerts[23].set(1.0F, 1.0F, 1.0F);
tempTexCoords = new Tyra::Vec4[tempVertsStsCount];
tempTexCoords[0].set(0.000618F, 0.937685F, 1.0F, 0.0F);
tempTexCoords[1].set(0.062592F, 0.937685F, 1.0F, 0.0F);
tempTexCoords[2].set(0.062592F, 0.999658F, 1.0F, 0.0F);
tempTexCoords[3].set(0.000618F, 0.999658F, 1.0F, 0.0F);
tempTexCoords[4].set(0.062608F, 0.937379F, 1.0F, 0.0F);
tempTexCoords[5].set(0.062576F, 0.999352F, 1.0F, 0.0F);
tempTexCoords[6].set(0.000602F, 0.999320F, 1.0F, 0.0F);
tempTexCoords[7].set(0.000634F, 0.937346F, 1.0F, 0.0F);
tempTexCoords[8].set(0.062592F, 0.937381F, 1.0F, 0.0F);
tempTexCoords[9].set(0.062592F, 0.999354F, 1.0F, 0.0F);
tempTexCoords[10].set(0.000618F, 0.999354F, 1.0F, 0.0F);
tempTexCoords[11].set(0.000618F, 0.937381F, 1.0F, 0.0F);
tempTexCoords[12].set(0.062618F, 0.937600F, 1.0F, 0.0F);
tempTexCoords[13].set(0.062618F, 0.999542F, 1.0F, 0.0F);
tempTexCoords[14].set(0.000603F, 0.999576F, 1.0F, 0.0F);
tempTexCoords[15].set(0.000616F, 0.937585F, 1.0F, 0.0F);
tempTexCoords[16].set(0.062561F, 0.937533F, 1.0F, 0.0F);
tempTexCoords[17].set(0.062561F, 0.999446F, 1.0F, 0.0F);
tempTexCoords[18].set(0.000649F, 0.999446F, 1.0F, 0.0F);
tempTexCoords[19].set(0.000649F, 0.937533F, 1.0F, 0.0F);
tempTexCoords[20].set(0.000556F, 0.937533F, 1.0F, 0.0F);
tempTexCoords[21].set(0.062530F, 0.937533F, 1.0F, 0.0F);
tempTexCoords[22].set(0.062530F, 0.999506F, 1.0F, 0.0F);
tempTexCoords[23].set(0.000556F, 0.999506F, 1.0F, 0.0F);
// Because 16 blocks can fit in single column of 256x256 tex atlas
offset = 1.0F / 16.0F;
for (u32 i = 0; i < tempVertsStsCount; i++)
tempTexCoords[i].y = 1.0F - tempTexCoords[i].y;
tempVertFaces = new u32[36];
tempTexCoordsFaces = new u32[36];
std::string vertexFaces =
"1,2,3,1,3,4,5,6,7,5,7,8,9,10,11,9,11,12,13,14,15,13,15,16,17,18,19,17,"
"19,20,21,22,23,21,23,24";
std::stringstream ssVertexFaces(vertexFaces);
std::string texCoordFaces =
"1,2,3,1,3,4,5,6,7,5,7,8,9,10,11,9,11,12,13,14,15,13,15,16,17,18,19,17,"
"19,20,21,22,23,21,23,24";
std::stringstream ssTexCoordFaces(texCoordFaces);
int i = 0;
std::string item;
while (std::getline(ssVertexFaces, item, ','))
tempVertFaces[i++] = std::stoi(item) - 1;
i = 0;
while (std::getline(ssTexCoordFaces, item, ','))
tempTexCoordsFaces[i++] = std::stoi(item) - 1;
}
void McpipSingleTexBlockData::unroll() {
count = 36;
comboData = new Tyra::Vec4[36 * 2];
vertices = &comboData[0];
textureCoords = &comboData[36];
for (u32 i = 0; i < count; i++) {
vertices[i] = tempVerts[tempVertFaces[i]];
textureCoords[i] = tempTexCoords[tempTexCoordsFaces[i]];
}
}
void McpipSingleTexBlockData::dellocateTempData() {
delete[] tempVerts;
delete[] tempTexCoords;
delete[] tempVertFaces;
delete[] tempTexCoordsFaces;
}
} // namespace Tyra
@@ -0,0 +1,143 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include <tamtypes.h>
#include "renderer/3d/pipeline/minecraft/minecraft_pipeline.hpp"
#include "thread/threading.hpp"
namespace Tyra {
MinecraftPipeline::MinecraftPipeline() { latestMode = UndefinedMcpipProgram; }
MinecraftPipeline::~MinecraftPipeline() {
if (bbox) {
delete bbox;
}
}
void MinecraftPipeline::init(RendererCore* core) {
rendererCore = core;
manager.init(core);
initBBox();
}
void MinecraftPipeline::onUse() {
manager.uploadVU1Programs();
changeMode(McPipCull, true);
}
void MinecraftPipeline::initBBox() {
const auto& block = manager.getBlockData();
bbox = new RenderBBox(block.vertices, block.count);
}
void MinecraftPipeline::render(McpipBlock* blocks, const u32& count,
Texture* t_tex, const bool& isMulti,
const bool& noClipChecks) {
auto texBuffers = rendererCore->texture.useTexture(t_tex);
rendererCore->gs.prim.mapping = 1;
manager.clearLastProgram();
std::vector<u32> cullIndexes;
if (noClipChecks) {
for (u32 i = 0; i < count; i++) cullIndexes.push_back(i);
cull(blocks, cullIndexes, &texBuffers, isMulti);
} else {
u32 culled = 0, clipped = 0;
std::vector<u32> clipIndexes;
for (u32 i = 0; i < count; i++) {
auto frustum = isInFrustum(blocks[i]);
if (frustum == CoreBBoxFrustum::IN_FRUSTUM) {
cullIndexes.push_back(i);
culled++;
} else if (frustum == CoreBBoxFrustum::PARTIALLY_IN_FRUSTUM) {
clipIndexes.push_back(i);
clipped++;
}
}
if (culled > 0) cull(blocks, cullIndexes, &texBuffers, isMulti);
if (clipped > 0) clip(blocks, clipIndexes, &texBuffers, isMulti);
}
Threading::switchThread();
}
CoreBBoxFrustum MinecraftPipeline::isInFrustum(const McpipBlock& block) const {
const auto* frustumPlanes = rendererCore->renderer3D.frustumPlanes.getAll();
return bbox->clipIsInFrustum(frustumPlanes, block.model);
}
void MinecraftPipeline::cull(McpipBlock* blocks,
const std::vector<u32>& indexes,
RendererCoreTextureBuffers* texBuffers,
const bool& isMulti) {
changeMode(McPipCull, false);
auto maxBlocksPerQBuffer = manager.culler.getMaxBlocksCountPerQBuffer();
auto partsCount = static_cast<u32>(
ceil(indexes.size() / static_cast<float>(maxBlocksPerQBuffer)));
for (u32 i = 0; i < partsCount; i++) {
u32 subArraySize = i != partsCount - 1
? maxBlocksPerQBuffer
: indexes.size() - i * maxBlocksPerQBuffer;
McpipBlock** blockPointerArray = new McpipBlock*[subArraySize];
u32 blockPointerArrayCount = 0;
for (u32 j = 0; j < subArraySize; j++) {
blockPointerArray[blockPointerArrayCount++] =
&blocks[indexes[i * maxBlocksPerQBuffer + j]];
}
manager.cull(blockPointerArray, blockPointerArrayCount, texBuffers,
isMulti);
delete[] blockPointerArray;
}
}
// -- 2nd qbuff = 36 * 3 (ST,RGBA,STQ)
// * 2 (We will have at least 2x more verts after clip)
// + Set, lod, set, clut, prim = 221
// -- 1st qbuff: 500 - 221 = 279
// Tags: 279 - for example 20 = 259
// Vert + ST from EE = 259 / 2 = 129 verts | OK!
void MinecraftPipeline::clip(McpipBlock* blocks,
const std::vector<u32>& indexes,
RendererCoreTextureBuffers* texBuffers,
const bool& isMulti) {
changeMode(McPipAsIs, false);
for (u32 i = 0; i < indexes.size(); i++) {
manager.clip(&blocks[indexes[i]], texBuffers, isMulti);
}
}
void MinecraftPipeline::changeMode(const McpipProgramName& requestedMode,
const u8& force) {
if (!force) {
if (latestMode == requestedMode) return;
}
if (requestedMode == McPipCull) {
manager.culler.configureVU1AndSendStaticData();
latestMode = McPipCull;
} else {
manager.clipper.configureVU1AndSendStaticData();
latestMode = McPipAsIs;
}
}
} // namespace Tyra
@@ -0,0 +1,34 @@
;//--------------------------------------------------------------------------------
;// MinecraftPipeline cull macros library
;//--------------------------------------------------------------------------------
;//---------------------------------------------------------
;// LoadStaticData - Load lod, set and viewproj matrix
;//---------------------------------------------------------
#macro LoadStaticData: t_lod, t_set
lq t_lod, VU1_MCPIP_AS_IS_STATIC_LOD(vi00)
lq t_set, VU1_MCPIP_AS_IS_STATIC_SET_TAG(vi00)
#endmacro
;//---------------------------------------------------------
;// LoadDynamicData - Load scale, prim and clut
;//---------------------------------------------------------
#macro LoadDynamicData: t_scale, t_prim, t_clut, t_color, t_vertexCount, t_buffer
lq t_scale, VU1_MCPIP_AS_IS_DYNAMIC_SCALE(t_buffer)
lq t_prim, VU1_MCPIP_AS_IS_DYNAMIC_PRIM(t_buffer)
lq t_clut, VU1_MCPIP_AS_IS_DYNAMIC_CLUT(t_buffer)
lq t_color, VU1_MCPIP_AS_IS_DYNAMIC_COLOR(t_buffer)
ilw.w t_vertexCount, VU1_MCPIP_AS_IS_DYNAMIC_SCALE(t_buffer)
#endmacro
;//---------------------------------------------------------
;// StoreTags - Store lod, prim, clut
;//---------------------------------------------------------
#macro StoreTags: t_lodTag, t_setTag, t_primTag, t_clut, t_destAddress
sq t_setTag, 0(t_destAddress)
sq t_lodTag, 1(t_destAddress)
sq t_setTag, 2(t_destAddress)
sq t_clut, 3(t_destAddress)
sq t_primTag, 4(t_destAddress)
iaddiu t_destAddress, t_destAddress, 5
#endmacro
@@ -0,0 +1,118 @@
; ______ ____ ___
; | \/ ____| |___|
; | | | \ | |
;---------------------------------------------------------------
; Copyright 2022, tyra - https://github.com/h4570/tyra
; Licenced under Apache License 2.0
; Sandro Sobczyński <sandro.sobczynski@gmail.com>
;
;---------------------------------------------------------------
; Super fast renderer of minecraft blocks.
; Block data is statically allocated in vi00
;
; - Triangle list
; - AsIs = NO TRANSFORM
; - Colors
;---------------------------------------------------------------
.syntax new
.name VU1BlocksAsIs
.vu
.init_vf_all
.init_vi_all
#include "src/renderer/core/paths/path1/programs/vcl_sml.i"
#include "inc/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_vu1_as_is_shared_defines.h"
#include "src/renderer/3d/pipeline/minecraft/programs/as_is/macros.i"
#define STQ_STORE_OFFSET 0
#define RGBA_STORE_OFFSET 1
#define XYZ2_STORE_OFFSET 2
--enter
--endenter
#vuprog VU1BlocksAsIs
LoadStaticData{ lodTag, setTag }
begin:
xtop buffer
LoadDynamicData{ scale, primTag, clut, color, vertexCount, buffer }
iaddiu vertexData, buffer, VU1_MCPIP_AS_IS_DYNAMIC_VERTEX_DATA_ADDR
iadd stqData, vertexData, vertexCount
iadd destAddress, stqData, vertexCount
iadd kickAddress, stqData, vertexCount
StoreTags{ lodTag, setTag, primTag, clut, destAddress }
FixColor{ color }
;--- Loop
iadd vertexCounter, buffer, vertexCount
vertexLoop:
;--- Load vertex1
lq vertex1, (vertexData)
lq stq1, (stqData)
;--- Load vertex2
lq vertex2, 1(vertexData)
lq stq2, 1(stqData)
;--- Load vertex3
lq vertex3, 2(vertexData)
lq stq3, 2(stqData)
;--- Calculate vertex1
ScaleVertexToGSFormat{ scale, vertex1 }
div q, vf00[w], vertex1[w]
PerformTexturePerspectiveCorrection{ outputStq1, stq1 }
;--- Calculate vertex2
ScaleVertexToGSFormat{ scale, vertex2 }
div q, vf00[w], vertex2[w]
PerformTexturePerspectiveCorrection{ outputStq2, stq2 }
;--- Calculate vertex3
ScaleVertexToGSFormat{ scale, vertex3 }
div q, vf00[w], vertex3[w]
PerformTexturePerspectiveCorrection{ outputStq3, stq3 }
;--- Store vertex1
sq outputStq1, STQ_STORE_OFFSET(destAddress)
sq color, RGBA_STORE_OFFSET(destAddress)
sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress)
;--- Store vertex2
sq outputStq2, STQ_STORE_OFFSET+3(destAddress)
sq color, RGBA_STORE_OFFSET+3(destAddress)
sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress)
;--- Store vertex3
sq outputStq3, STQ_STORE_OFFSET+6(destAddress)
sq color, RGBA_STORE_OFFSET+6(destAddress)
sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress)
;-------------------------------
iaddiu vertexData, vertexData, 3
iaddiu stqData, stqData, 3
iaddiu destAddress, destAddress, 9
;--- Fix loop
iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter
ibne vertexCounter, buffer, vertexLoop ; and repeat if needed
xgkick kickAddress ; dispatch to the GS rasterizer.
--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it...
--cont
b begin
#endvuprog
--exit
--endexit
@@ -0,0 +1,28 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/minecraft/programs/as_is/mcpip_as_is_vu1_program.hpp"
extern u32 VU1BlocksAsIs_CodeStart __attribute__((section(".vudata")));
extern u32 VU1BlocksAsIs_CodeEnd __attribute__((section(".vudata")));
namespace Tyra {
McpipAsIsVU1Program::McpipAsIsVU1Program()
: McpipProgram(McpipProgramName::McPipAsIs, &VU1BlocksAsIs_CodeStart,
&VU1BlocksAsIs_CodeEnd) {}
McpipAsIsVU1Program::~McpipAsIsVU1Program() {}
std::string McpipAsIsVU1Program::getStringName() const {
return std::string("As is");
}
} // namespace Tyra
@@ -0,0 +1,162 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/minecraft/programs/as_is/mcpip_clip.hpp"
namespace Tyra {
McpipClip::McpipClip() {
staticPacket = packet2_create(8, P2_TYPE_NORMAL, P2_MODE_CHAIN, true);
algoSettings.lerpColors = false;
algoSettings.lerpTexCoords = true;
algoSettings.lerpNormals = false;
}
McpipClip::~McpipClip() { packet2_free(staticPacket); }
void McpipClip::init(RendererCore* core, McpipBlockData* t_singleBlockData,
McpipBlockData* t_multiBlockData) {
singleBlockData = t_singleBlockData;
multiBlockData = t_multiBlockData;
rendererCore = core;
algorithm.init(rendererCore->getSettings());
setDBufferSize();
initStaticPacket();
}
u32 McpipClip::uploadVU1Program(McpipProgramsRepository* repo,
const u32& addr) {
auto* program = repo->getProgram(McpipProgramName::McPipAsIs);
return rendererCore->renderer3D.uploadVU1Program(program, addr);
}
void McpipClip::configureVU1AndSendStaticData() {
u16 start = VU1_MCPIP_AS_IS_STATIC_LAST_DATA_ADDR + 1;
rendererCore->renderer3D.setVU1DoubleBuffers(start, vu1DBufferSize);
sendVU1StaticData();
}
void McpipClip::initStaticPacket() {
packet2_utils_vu_open_unpack(staticPacket, VU1_MCPIP_AS_IS_STATIC_LOD, false);
{
packet2_utils_gs_add_lod(staticPacket, &rendererCore->gs.lod);
packet2_utils_gif_add_set(staticPacket, 1);
}
packet2_utils_vu_close_unpack(staticPacket);
packet2_utils_vu_add_end_tag(staticPacket);
}
void McpipClip::addData(McpipBlock* block, const bool& isMulti,
RendererCoreTextureBuffers* texBuffers,
packet2_t* packet, const u8& context) {
std::vector<Path1ClipVertex> clippedVertices;
auto mvp = rendererCore->renderer3D.getViewProj() * block->model;
const auto* blockData = isMulti ? multiBlockData : singleBlockData;
for (u32 i = 0; i < blockData->count / 3; i++) {
for (u8 j = 0; j < 3; j++) {
Path1ClipVertex vert = {mvp * blockData->vertices[i * 3 + j], Vec4(),
blockData->textureCoords[i * 3 + j], Vec4()};
inputTriangle.push_back(vert);
}
clippedTriangle.clear();
algorithm.clip(&clippedTriangle, inputTriangle, algoSettings);
inputTriangle.clear();
if (clippedTriangle.size() == 0) continue;
auto va = clippedTriangle.at(0);
for (u32 j = 1; j <= clippedTriangle.size() - 2; j++) {
auto vb = clippedTriangle.at(j);
auto vc = clippedTriangle.at((j + 1) % clippedTriangle.size());
clippedVertices.push_back(va);
clippedVertices.push_back(vb);
clippedVertices.push_back(vc);
}
}
addCorrections(&clippedVertices, block);
moveDataToBuffer(&clippedVertices, context);
addDataToPacket(packet, context, block, clippedVertices.size(), texBuffers);
}
void McpipClip::addCorrections(std::vector<Path1ClipVertex>* vertices,
McpipBlock* block) {
for (u32 i = 0; i < vertices->size(); i++) {
(*vertices)[i].position /= (*vertices)[i].position.w; // Perspective divide
(*vertices)[i].st += block->textureOffset; // Texture offset
}
}
void McpipClip::moveDataToBuffer(std::vector<Path1ClipVertex>* vertices,
const u8& context) {
for (u32 i = 0; i < vertices->size(); i++) {
vertexBuffers[context][i].set(vertices->at(i).position);
texCoordBuffers[context][i].set(vertices->at(i).st);
}
}
void McpipClip::addDataToPacket(packet2_t* packet, const u8& context,
McpipBlock* block, const int& count,
RendererCoreTextureBuffers* texBuffers) {
packet2_reset(packet, false);
rendererCore->texture.updateClutBuffer(texBuffers->clut);
packet2_utils_vu_open_unpack(packet, VU1_MCPIP_AS_IS_DYNAMIC_SCALE, true);
{
packet2_add_float(packet, 2048.0F); // scale
packet2_add_float(packet, 2048.0F); // scale
packet2_add_float(packet,
static_cast<float>(0xFFFFFF) / 32.0F); // scale
packet2_add_s32(packet, count); // vertex count
packet2_utils_gs_add_prim_giftag(packet, &rendererCore->gs.prim, count,
((u64)GIF_REG_ST) << 0 |
((u64)GIF_REG_RGBAQ) << 4 |
((u64)GIF_REG_XYZ2) << 8,
3, 0);
packet2_utils_gs_add_texbuff_clut(packet, texBuffers->core,
&rendererCore->texture.clut);
Packet2TyraUtils::addColor(packet, block->color);
}
packet2_utils_vu_close_unpack(packet);
u32 addr = VU1_MCPIP_AS_IS_DYNAMIC_VERTEX_DATA_ADDR;
packet2_utils_vu_add_unpack_data(packet, addr, vertexBuffers[context], count,
true);
addr += count;
packet2_utils_vu_add_unpack_data(packet, addr, texCoordBuffers[context],
count, true);
}
void McpipClip::setDBufferSize() {
vu1DBufferSize = 1000; // VU1 mem size
vu1DBufferSize -= VU1_MCPIP_AS_IS_STATIC_LAST_DATA_ADDR; // static data
vu1DBufferSize -= 1;
vu1DBufferSize /= 2; // xtop double buffer
}
void McpipClip::sendVU1StaticData() {
dma_channel_wait(DMA_CHANNEL_VIF1, 0);
dma_channel_send_packet2(staticPacket, DMA_CHANNEL_VIF1, true);
}
} // namespace Tyra
@@ -0,0 +1,93 @@
;//--------------------------------------------------------------------------------
;// MinecraftPipeline cull macros library
;//--------------------------------------------------------------------------------
;//---------------------------------------------------------
;// StoreBlockizerStaticData - Load and store lod, clut and prim.
;// Push dest address by 5 qwords
;//---------------------------------------------------------
#macro StoreBlockizerLodClutTexPrim: t_destAddr, t_clutTex
lq setTag, VU1_MCPIP_CULL_STATIC_SET_TAG(vi00)
lq lodTag, VU1_MCPIP_CULL_STATIC_LOD(vi00)
sq setTag, 0(t_destAddr)
sq lodTag, 1(t_destAddr)
sq setTag, 2(t_destAddr)
sq t_clutTex, 3(t_destAddr)
lq primTag, VU1_MCPIP_CULL_STATIC_PRIM(vi00)
sq primTag, 4(t_destAddr)
iaddiu t_destAddr, t_destAddr, 5
#endmacro
;//---------------------------------------------------------
;// GetDestinationAddress - Load VU1 options and check
;// in which double buffer we are. If 0, return first double buff
;// if 1, return second double buffer.
;// Also toggle VU1 dbuff option, so next call of this macro will result
;// opposite buffer.
;//---------------------------------------------------------
#macro GetDestinationAddress: t_destAddr, t_kickAddr
ilw.w static1, VU1_MCPIP_CULL_STATIC_VU1_OPTIONS(vi00)
ilw.x currDBufferOffset, VU1_MCPIP_CULL_STATIC_VU1_OPTIONS(vi00)
ibgtz currDBufferOffset, get_dest_addr_second
get_dest_addr_first:
iaddiu t_destAddr, vi00, VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF1_ADDR
isw.x static1, VU1_MCPIP_CULL_STATIC_VU1_OPTIONS(vi00)
b get_dest_addr_finish
get_dest_addr_second:
iaddiu t_destAddr, vi00, VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF2_ADDR
isw.x vi00, VU1_MCPIP_CULL_STATIC_VU1_OPTIONS(vi00)
get_dest_addr_finish:
iaddiu t_kickAddr, t_destAddr, 0
#endmacro
;//---------------------------------------------------------
;// LoadScaleAndBlocksCount - Load scale vec3 and blocks count
;// from w component
;//---------------------------------------------------------
#macro LoadBufferDynamicData: t_buffer, t_scale, t_clutTex, t_blocksCount, t_viewProj
lq.xyz t_scale, VU1_MCPIP_CULL_DYNAMIC_SCALE_AND_BLOCKS_COUNT_ADDR(t_buffer)
ilw.w t_blocksCount, VU1_MCPIP_CULL_DYNAMIC_SCALE_AND_BLOCKS_COUNT_ADDR(t_buffer)
lq t_clutTex, VU1_MCPIP_CULL_DYNAMIC_CLUT_TEX(t_buffer)
lq t_viewProj[0], 0+VU1_MCPIP_CULL_DYNAMIC_VIEW_PROJ_MATRIX_ADDR(t_buffer)
lq t_viewProj[1], 1+VU1_MCPIP_CULL_DYNAMIC_VIEW_PROJ_MATRIX_ADDR(t_buffer)
lq t_viewProj[2], 2+VU1_MCPIP_CULL_DYNAMIC_VIEW_PROJ_MATRIX_ADDR(t_buffer)
lq t_viewProj[3], 3+VU1_MCPIP_CULL_DYNAMIC_VIEW_PROJ_MATRIX_ADDR(t_buffer)
#endmacro
;//---------------------------------------------------------
;// GetVertAndStData - Get static vertex data and tex coords
;//---------------------------------------------------------
#macro GetVertAndStData: t_vertData, t_stData
iaddiu t_vertData, vi00, VU1_MCPIP_CULL_STATIC_VERTEX_DATA
iaddiu t_stData, vi00, VU1_MCPIP_CULL_STATIC_TEX_COORD_DATA
#endmacro
;//---------------------------------------------------------
;// GetBlockData - Get mvp matrix, color, st offset for single block
;//---------------------------------------------------------
#macro GetBlockData: t_blockData, t_model, t_color, t_stOffset
lq t_model[0], 0(t_blockData)
lq t_model[1], 1(t_blockData)
lq t_model[2], 2(t_blockData)
lq t_model[3], 3(t_blockData)
lq t_color, 4(t_blockData)
lq t_stOffset, 5(t_blockData)
#endmacro
;//---------------------------------------------------------
;// GetVertexData - Get vertex and tex coord
;//---------------------------------------------------------
#macro GetVertexData: t_vertData, t_stqData, t_vertex, t_stq, t_offset
lq t_vertex, t_offset(t_vertData)
lq t_stq, t_offset(t_stqData)
#endmacro
;//---------------------------------------------------------
;// GetVertexData - Get vertex and tex coord
;//---------------------------------------------------------
#macro AddSTOffset: t_stq, t_stqOffset
add t_stq, t_stq, t_stqOffset
#endmacro
@@ -0,0 +1,139 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull.hpp"
namespace Tyra {
McpipCull::McpipCull() {
staticPacket = packet2_create(8, P2_TYPE_NORMAL, P2_MODE_CHAIN, true);
}
McpipCull::~McpipCull() { packet2_free(staticPacket); }
void McpipCull::init(RendererCore* core, McpipBlockData* t_blockData) {
blockData = t_blockData;
rendererCore = core;
initStaticPacket();
setDBufferSize();
}
void McpipCull::setDBufferSize() {
vu1DBufferSize = 1000; // VU1 mem size
vu1DBufferSize -= VU1_MCPIP_CULL_STATIC_LAST_DATA_ADDR; // static data
// Our additional, mini output double buffer at the bottom of VU1 mem
u16 miniOutputDoubleBufferSize =
blockData->count * 3 +
5; // 36 * (ST, XYZ2, RGBAQ) + Set, lod, set, clut, prim
vu1DBufferSize -= miniOutputDoubleBufferSize; // First
vu1DBufferSize -= miniOutputDoubleBufferSize; // Second
TYRA_ASSERT(1000 - (miniOutputDoubleBufferSize * 2) ==
VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF1_ADDR,
"There is mismatch in output dbuffer1 size. Should be: ",
1000 - (miniOutputDoubleBufferSize * 2),
"but is: ", VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF1_ADDR);
TYRA_ASSERT(1000 - miniOutputDoubleBufferSize ==
VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF2_ADDR,
"There is mismatch in output dbuffer2 size. Should be: ",
1000 - miniOutputDoubleBufferSize,
"but is: ", VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF2_ADDR);
vu1DBufferSize /= 2; // xtop double buffer
}
u32 McpipCull::uploadVU1Program(McpipProgramsRepository* repo,
const u32& addr) {
auto* program = repo->getProgram(McpipProgramName::McPipCull);
return rendererCore->renderer3D.uploadVU1Program(program, addr);
}
void McpipCull::configureVU1AndSendStaticData() {
rendererCore->renderer3D.setVU1DoubleBuffers(
VU1_MCPIP_CULL_STATIC_LAST_DATA_ADDR, vu1DBufferSize);
sendVU1StaticData();
}
u32 McpipCull::getMaxBlocksCountPerQBuffer() const {
u32 result = vu1DBufferSize;
result -= 1; // VU1_MCPIP_CULL_DYNAMIC_SCALE_AND_BLOCKS_COUNT;
result -= 1; // Lod tag
result -= 4; // View proj
result /= VU1_MCPIP_CULL_QWORDS_PER_BLOCK;
return result;
}
void McpipCull::initStaticPacket() {
packet2_utils_vu_open_unpack(staticPacket, VU1_MCPIP_CULL_STATIC_LOD, false);
{
packet2_utils_gs_add_lod(staticPacket, &rendererCore->gs.lod);
packet2_utils_gs_add_prim_giftag(staticPacket, &rendererCore->gs.prim, 36,
((u64)GIF_REG_ST) << 0 |
((u64)GIF_REG_RGBAQ) << 4 |
((u64)GIF_REG_XYZ2) << 8,
3, 0);
packet2_utils_gif_add_set(staticPacket, 1);
packet2_add_u32(staticPacket, 0); // Param1 - Mini double buffer switcher
packet2_add_u32(staticPacket, 0);
packet2_add_u32(staticPacket, 0);
packet2_add_u32(staticPacket,
1); // static 1 - used in VU1's GetDestinationAddress{}
}
packet2_utils_vu_close_unpack(staticPacket);
packet2_utils_vu_add_end_tag(staticPacket);
}
void McpipCull::sendVU1StaticData() {
dma_channel_wait(DMA_CHANNEL_VIF1, 0);
dma_channel_send_packet2(staticPacket, DMA_CHANNEL_VIF1, true);
}
void McpipCull::addData(packet2_t* packet, McpipBlock** blockPointerArray,
u32 blockPointerArrayCount,
RendererCoreTextureBuffers* texBuffers, bool isMulti) {
packet2_reset(packet, false);
rendererCore->texture.updateClutBuffer(texBuffers->clut);
packet2_utils_vu_open_unpack(
packet, VU1_MCPIP_CULL_DYNAMIC_SCALE_AND_BLOCKS_COUNT_ADDR, true);
{
packet2_add_float(packet, 2048.0F); // scale
packet2_add_float(packet, 2048.0F); // scale
packet2_add_float(packet,
static_cast<float>(0xFFFFFF) / 32.0F); // scale
packet2_add_u32(packet, blockPointerArrayCount); // blocks count
packet2_utils_gs_add_texbuff_clut(packet, texBuffers->core,
&rendererCore->texture.clut);
Packet2TyraUtils::addM4x4(packet, rendererCore->renderer3D.getViewProj());
}
packet2_utils_vu_close_unpack(packet);
u32 addr = VU1_MCPIP_CULL_DYNAMIC_BLOCKS_DATA;
for (u32 i = 0; i < blockPointerArrayCount; i++) {
packet2_utils_vu_add_unpack_data(packet, addr, blockPointerArray[i],
VU1_MCPIP_CULL_QWORDS_PER_BLOCK, true);
addr += VU1_MCPIP_CULL_QWORDS_PER_BLOCK;
}
}
} // namespace Tyra
@@ -0,0 +1,129 @@
; ______ ____ ___
; | \/ ____| |___|
; | | | \ | |
;---------------------------------------------------------------
; Copyright 2022, tyra - https://github.com/h4570/tyra
; Licenced under Apache License 2.0
; Sandro Sobczyński <sandro.sobczynski@gmail.com>
;
;---------------------------------------------------------------
; Super fast renderer of minecraft blocks.
; Block data is statically allocated in vi00
;
; - Triangle list
; - Cull = transform
; - Colors
;---------------------------------------------------------------
.syntax new
.name VU1BlocksCull
.vu
.init_vf_all
.init_vi_all
#include "src/renderer/core/paths/path1/programs/vcl_sml.i"
#include "inc/renderer/3d/pipeline/minecraft/programs/cull/mcpip_vu1_cull_shared_defines.h"
#include "src/renderer/3d/pipeline/minecraft/programs/cull/macros.i"
#define STQ_STORE_OFFSET 0
#define RGBA_STORE_OFFSET 1
#define XYZ2_STORE_OFFSET 2
--enter
--endenter
#vuprog VU1BlocksCull
GetVertAndStData{ staticVertexData, staticStqData }
ResetClipFlags{ }
begin:
xtop buffer
iaddiu blockData, buffer, VU1_MCPIP_CULL_DYNAMIC_BLOCKS_DATA
LoadBufferDynamicData{ buffer, scale, clutTex, blocksCount, viewProj }
;--- Loop
iadd blockCounter, buffer, blocksCount
blocksLoop:
GetBlockData{ blockData, model, color, stOffset }
MatrixMultiply{ mvp, model, viewProj }
FixColor{ color }
GetDestinationAddress{ destAddress, kickAddress }
StoreBlockizerLodClutTexPrim{ destAddress, clutTex }
iaddiu vertexData, staticVertexData, 0
iaddiu stqData, staticStqData, 0
iaddiu vertexCounter, buffer, VU1_MCPIP_CULL_VERTEX_COUNT
vertexLoop:
GetVertexData{ vertexData, stqData, vertex1, stq1, 0 }
GetVertexData{ vertexData, stqData, vertex2, stq2, 1 }
GetVertexData{ vertexData, stqData, vertex3, stq3, 2 }
;--- Calculate vertex1
MatrixMultiplyVertex{ vertex1, mvp, vertex1 }
PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET }
VertexPersCorr{ vertex1, vertex1 }
ScaleVertexToGSFormat{ scale, vertex1 }
AddSTOffset{ stq1, stOffset }
PerformTexturePerspectiveCorrection{ outputStq1, stq1 }
;--- Calculate vertex2
MatrixMultiplyVertex{ vertex2, mvp, vertex2 }
PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET+3 }
VertexPersCorr{ vertex2, vertex2 }
ScaleVertexToGSFormat{ scale, vertex2 }
AddSTOffset{ stq2, stOffset }
PerformTexturePerspectiveCorrection{ outputStq2, stq2 }
;--- Calculate vertex3
MatrixMultiplyVertex{ vertex3, mvp, vertex3 }
PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET+6 }
VertexPersCorr{ vertex3, vertex3 }
ScaleVertexToGSFormat{ scale, vertex3 }
AddSTOffset{ stq3, stOffset }
PerformTexturePerspectiveCorrection{ outputStq3, stq3 }
;--- Store vertex1
sq outputStq1, STQ_STORE_OFFSET(destAddress)
sq color, RGBA_STORE_OFFSET(destAddress)
sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress)
;--- Store vertex2
sq outputStq2, STQ_STORE_OFFSET+3(destAddress)
sq color, RGBA_STORE_OFFSET+3(destAddress)
sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress)
;--- Store vertex3
sq outputStq3, STQ_STORE_OFFSET+6(destAddress)
sq color, RGBA_STORE_OFFSET+6(destAddress)
sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress)
iaddiu vertexData, vertexData, 3
iaddiu stqData, stqData, 3
iaddiu destAddress, destAddress, 9
iaddi vertexCounter, vertexCounter, -3
ibne vertexCounter, buffer, vertexLoop
; End of vertex loop
--barrier
xgkick kickAddress
iaddiu blockData, blockData, VU1_MCPIP_CULL_QWORDS_PER_BLOCK
iaddi blockCounter, blockCounter, -1
ibne blockCounter, buffer, blocksLoop
; End of block loop
--cont
b begin
#endvuprog
--exit
--endexit
@@ -0,0 +1,28 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull_vu1_program.hpp"
extern u32 VU1BlocksCull_CodeStart __attribute__((section(".vudata")));
extern u32 VU1BlocksCull_CodeEnd __attribute__((section(".vudata")));
namespace Tyra {
McpipCullVU1Program::McpipCullVU1Program()
: McpipProgram(McpipProgramName::McPipCull, &VU1BlocksCull_CodeStart,
&VU1BlocksCull_CodeEnd) {}
McpipCullVU1Program::~McpipCullVU1Program() {}
std::string McpipCullVU1Program::getStringName() const {
return std::string("Cull");
}
} // namespace Tyra
@@ -0,0 +1,23 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/minecraft/programs/mcpip_program.hpp"
namespace Tyra {
McpipProgram::McpipProgram(const McpipProgramName& t_name, u32* t_start,
u32* t_end)
: VU1Program(t_start, t_end), name(t_name) {}
McpipProgram::~McpipProgram() {}
const McpipProgramName& McpipProgram::getName() const { return name; }
} // namespace Tyra
@@ -0,0 +1,130 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/minecraft/programs/mcpip_programs_manager.hpp"
namespace Tyra {
BlockizerProgramsManager::BlockizerProgramsManager() {
lastProgramName = UndefinedMcpipProgram;
context = 0;
vu1BlockData = BlockNotUploaded;
dynamicPackets[0] = packet2_create(100, P2_TYPE_NORMAL, P2_MODE_CHAIN, true);
dynamicPackets[1] = packet2_create(100, P2_TYPE_NORMAL, P2_MODE_CHAIN, true);
staticPacket = packet2_create(2, P2_TYPE_NORMAL, P2_MODE_CHAIN, true);
setProgramsCache();
}
BlockizerProgramsManager::~BlockizerProgramsManager() {
packet2_free(dynamicPackets[0]);
packet2_free(dynamicPackets[1]);
packet2_free(staticPacket);
packet2_free(programsPacket);
}
void BlockizerProgramsManager::init(RendererCore* core) {
culler.init(core, &singleTexBlockData);
clipper.init(core, &singleTexBlockData, &multiTexBlockData);
}
void BlockizerProgramsManager::setProgramsCache() {
VU1Program** programs = new VU1Program*[2];
programs[0] = repo.getProgram(McpipProgramName::McPipCull);
programs[1] = repo.getProgram(McpipProgramName::McPipAsIs);
programsPacket =
renderer->core.getPath1()->createProgramsCache(programs, 2, 0);
delete[] programs;
}
void BlockizerProgramsManager::uploadVU1Programs() {
dma_channel_wait(DMA_CHANNEL_VIF1, 0);
dma_channel_send_packet2(programsPacket, DMA_CHANNEL_VIF1, true);
dma_channel_wait(DMA_CHANNEL_VIF1, 0);
lastProgramName = UndefinedMcpipProgram;
vu1BlockData = BlockNotUploaded;
}
void BlockizerProgramsManager::uploadBlock(bool isMulti) {
if (vu1BlockData != BlockNotUploaded) {
if (isMulti && vu1BlockData == BlockMultiUploaded) {
return;
}
} else {
if (!isMulti && vu1BlockData == BlockSingleUploaded) {
return;
}
}
packet2_reset(staticPacket, false);
const McpipBlockData& blockData =
isMulti ? static_cast<McpipBlockData>(multiTexBlockData)
: static_cast<McpipBlockData>(singleTexBlockData);
packet2_utils_vu_add_unpack_data(
staticPacket, VU1_MCPIP_CULL_STATIC_VERTEX_DATA, blockData.comboData,
blockData.getComboCount(), false);
packet2_utils_vu_add_end_tag(staticPacket);
vu1BlockData = isMulti ? BlockMultiUploaded : BlockSingleUploaded;
dma_channel_wait(DMA_CHANNEL_VIF1, 0);
dma_channel_send_packet2(staticPacket, DMA_CHANNEL_VIF1, true);
}
void BlockizerProgramsManager::cull(McpipBlock** blockPointerArray,
u32 blockPointerArrayCount,
RendererCoreTextureBuffers* texBuffers,
const bool& isMulti) {
uploadBlock(isMulti);
auto* currentPacket = dynamicPackets[context];
auto* program = repo.getProgram(McpipProgramName::McPipCull);
culler.addData(currentPacket, blockPointerArray, blockPointerArrayCount,
texBuffers, isMulti);
sendPacket(program);
}
void BlockizerProgramsManager::clip(McpipBlock* block,
RendererCoreTextureBuffers* texBuffers,
const bool& isMulti) {
vu1BlockData = BlockNotUploaded;
auto* currentPacket = dynamicPackets[context];
auto* program = repo.getProgram(McpipProgramName::McPipAsIs);
clipper.addData(block, isMulti, texBuffers, currentPacket, context);
sendPacket(program);
}
void BlockizerProgramsManager::sendPacket(McpipProgram* program) {
auto* currentPacket = dynamicPackets[context];
if (lastProgramName != program->getName()) {
packet2_utils_vu_add_start_program(currentPacket,
program->getDestinationAddress());
lastProgramName = program->getName();
} else {
packet2_utils_vu_add_continue_program(currentPacket);
}
packet2_utils_vu_add_end_tag(currentPacket);
dma_channel_wait(DMA_CHANNEL_VIF1, 0);
dma_channel_send_packet2(currentPacket, DMA_CHANNEL_VIF1, true);
context = !context;
}
} // namespace Tyra
@@ -0,0 +1,33 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/minecraft/programs/mcpip_programs_repository.hpp"
namespace Tyra {
McpipProgramsRepository::McpipProgramsRepository() {}
McpipProgramsRepository::~McpipProgramsRepository() {}
McpipProgram* McpipProgramsRepository::getProgram(
const McpipProgramName& name) {
switch (name) {
case McpipProgramName::McPipCull:
return &cull;
case McpipProgramName::McPipAsIs:
return &asIs;
default:
TYRA_TRAP("Unknown VU1 program name");
return &cull;
}
}
} // namespace Tyra
@@ -0,0 +1,89 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include <tamtypes.h>
#include <string>
#include <sstream>
#include "renderer/3d/pipeline/std/core/bag/packaging/stdpip_bag_package.hpp"
namespace Tyra {
StdpipBagPackage::StdpipBagPackage() {
size = 0;
bag = nullptr;
vertices = nullptr;
sts = nullptr;
normals = nullptr;
colors = nullptr;
}
StdpipBagPackage::~StdpipBagPackage() {}
void StdpipBagPackage::print() const {
auto text = getPrint(nullptr);
printf("%s\n", text.c_str());
}
void StdpipBagPackage::print(const char* name) const {
auto text = getPrint(name);
printf("%s\n", text.c_str());
}
std::string StdpipBagPackage::getPrint(const char* name) const {
std::stringstream res;
if (name) {
res << name << "(";
} else {
res << "StdpipBagPackage(";
}
res << std::fixed << std::setprecision(2);
res << std::endl;
res << "Size: " << static_cast<int>(size) << std::endl;
res << "Vectors: " << std::endl;
for (u32 i = 0; i < size; i++) {
res << i << ": " << vertices[i].getPrint() << std::endl;
}
if (sts != nullptr) {
res << "STs: " << std::endl;
for (u32 i = 0; i < size; i++)
res << i << ": " << sts[i].getPrint() << std::endl;
}
if (colors != nullptr) {
res << "Colors: " << std::endl;
for (u32 i = 0; i < size; i++)
res << i << ": " << colors[i].getPrint() << std::endl;
}
if (normals != nullptr) {
res << "Normals: " << std::endl;
for (u32 i = 0; i < size; i++)
res << i << ": " << normals[i].getPrint() << std::endl;
}
res << "Is in frustum: ";
switch (isInFrustum) {
case CoreBBoxFrustum::IN_FRUSTUM:
res << "Yes";
break;
case CoreBBoxFrustum::OUTSIDE_FRUSTUM:
res << "No";
break;
case CoreBBoxFrustum::PARTIALLY_IN_FRUSTUM:
res << "Partially";
break;
}
res << ")";
return res.str();
}
} // namespace Tyra
@@ -0,0 +1,119 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include <tamtypes.h>
#include <math.h>
#include "debug/debug.hpp"
#include "renderer/3d/pipeline/std/core/bag/packaging/stdpip_bag_packager.hpp"
namespace Tyra {
StdpipBagPackager::StdpipBagPackager() {}
StdpipBagPackager::~StdpipBagPackager() {}
void StdpipBagPackager::init(Renderer3DFrustumPlanes* t_frustumPlanes) {
frustumPlanes = t_frustumPlanes;
}
/**
* @brief Create render packages from provided render data
*
* @param size Max maxVertCount verts (VU1 buffer size)
*/
StdpipBagPackage* StdpipBagPackager::create(u16* o_size, StdpipBag* data,
u16 size) {
TYRA_ASSERT(size <= maxVertCount, "StdpipBagPackage can have max ",
maxVertCount, " verts. Provided \"", size, "\"");
*o_size = ceil(data->count / static_cast<float>(size));
StdpipBagPackage* result = new StdpipBagPackage[*o_size];
for (u16 i = 0; i < *o_size; i++) {
result[i].bag = data;
result[i].vertices = &data->vertices[i * size];
if (data->texture) result[i].sts = &data->texture->coordinates[i * size];
if (data->color->many)
result[i].colors = reinterpret_cast<Vec4*>(&data->color->many[i * size]);
if (data->lighting) result[i].normals = &data->lighting->normals[i * size];
result[i].indexOf1By3BBox = (i * size) / (maxVertCount / 3);
if (i == *o_size - 1) {
result[i].size = data->count - i * size;
} else {
result[i].size = size;
}
result[i].isInFrustum = checkFrustum(result[i]);
}
return result;
}
/**
* @brief Split render package to smaller packages
*
* @param size Max maxVertCount verts (VU1 buffer size)
*/
StdpipBagPackage* StdpipBagPackager::create(u16* o_count,
const StdpipBagPackage& pkg,
u16 size) {
TYRA_ASSERT(size <= maxVertCount, "StdpipBagPackage can have max ",
maxVertCount, " verts. Provided \"", size, "\"");
*o_count = ceil(pkg.size / static_cast<float>(size));
auto* result = new StdpipBagPackage[*o_count];
for (u16 i = 0; i < *o_count; i++) {
result[i].bag = pkg.bag;
result[i].vertices = &pkg.vertices[i * size];
if (pkg.bag->texture) result[i].sts = &pkg.sts[i * size];
if (pkg.bag->color->many) result[i].colors = &pkg.colors[i * size];
if (pkg.bag->lighting) result[i].normals = &pkg.normals[i * size];
result[i].indexOf1By3BBox =
pkg.indexOf1By3BBox + ((i * size) / (maxVertCount / 3));
if (i == *o_count - 1) {
result[i].size = pkg.size - i * size;
} else {
result[i].size = size;
}
result[i].isInFrustum = checkFrustum(result[i]);
}
return result;
}
CoreBBoxFrustum StdpipBagPackager::checkFrustum(const StdpipBagPackage& pkg) {
if (pkg.size <= (maxVertCount / 3)) { // Is subpackage
auto& bbox = renderBBox->getChildBBox1By3(pkg.indexOf1By3BBox);
return bbox.clipIsInFrustum(frustumPlanes->getAll(), *pkg.bag->info->model);
} else { // Is package
auto bbox = renderBBox->createChildBBox(
pkg.indexOf1By3BBox,
ceil(pkg.size / static_cast<float>(maxVertCount / 3)));
return bbox.clipIsInFrustum(frustumPlanes->getAll(), *pkg.bag->info->model);
}
}
void StdpipBagPackager::setMaxVertCount(const u32& count) {
maxVertCount = count;
}
} // namespace Tyra
@@ -0,0 +1,113 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include <tamtypes.h>
#include <string>
#include <sstream>
#include <vector>
#include "debug/debug.hpp"
#include "renderer/3d/pipeline/std/core/bag/packaging/stdpip_bag_packages_bbox.hpp"
namespace Tyra {
StdpipBagPackagesBBox::StdpipBagPackagesBBox(Vec4* t_vertices, u32* t_faces,
const u32& t_facesCount,
const u32& t_maxVertCount) {
u32 splitPartSize = t_maxVertCount / 3;
vertexCount = t_facesCount;
partsCount = ceil(vertexCount / static_cast<float>(splitPartSize));
bboxParts = new std::vector<CoreBBox>;
for (u32 i = 0; i < partsCount; i++) {
u32 partSize =
i == partsCount - 1 ? t_facesCount - i * splitPartSize : splitPartSize;
bboxParts->push_back(
CoreBBox(t_vertices, t_faces + i * splitPartSize, partSize));
}
mainBBox = new RenderBBox(*bboxParts, 0, partsCount);
}
StdpipBagPackagesBBox::StdpipBagPackagesBBox(Vec4* t_vertices,
const u32& t_count,
const u32& t_maxVertCount) {
u32 splitPartSize = t_maxVertCount / 3;
vertexCount = t_count;
partsCount = ceil(vertexCount / static_cast<float>(splitPartSize));
bboxParts = new std::vector<CoreBBox>;
for (u32 i = 0; i < partsCount; i++) {
u32 partSize =
i == partsCount - 1 ? t_count - i * splitPartSize : splitPartSize;
bboxParts->push_back(RenderBBox(t_vertices + i * splitPartSize, partSize));
}
mainBBox = new RenderBBox(*bboxParts, 0, partsCount);
}
const RenderBBox& StdpipBagPackagesBBox::getChildBBox1By3(
const u32& index) const {
TYRA_ASSERT(index < partsCount,
"Index out of range. Provided index: ", index);
return static_cast<RenderBBox&>(bboxParts->at(index));
}
RenderBBox* StdpipBagPackagesBBox::getMainBBox() { return mainBBox; }
const u32& StdpipBagPackagesBBox::getPartsCount() const { return partsCount; }
const u32& StdpipBagPackagesBBox::getVertexCount() const { return vertexCount; }
RenderBBox StdpipBagPackagesBBox::createChildBBox(const u32& index,
const u16& partsSize) const {
return RenderBBox(*bboxParts, index, partsSize);
}
void StdpipBagPackagesBBox::print() const {
auto text = getPrint(nullptr);
printf("%s\n", text.c_str());
}
void StdpipBagPackagesBBox::print(const char* name) const {
auto text = getPrint(name);
printf("%s\n", text.c_str());
}
std::string StdpipBagPackagesBBox::getPrint(const char* name) const {
std::stringstream res;
if (name) {
res << name << "(";
} else {
res << "StdpipBagPackagesBBox(";
}
res << std::fixed << std::setprecision(2);
res << std::endl;
res << "Vertices count: " << static_cast<int>(vertexCount) << std::endl;
res << "Main CoreBBox: " << std::endl;
res << mainBBox->getPrint() << std::endl;
res << "Child BBoxes: " << std::endl;
for (u32 i = 0; i < partsCount; i++) {
res << i << ": " << bboxParts->at(i).getPrint();
if (i != partsCount - 1) {
res << std::endl;
}
}
res << ")";
return res.str();
}
StdpipBagPackagesBBox::~StdpipBagPackagesBBox() {
delete bboxParts;
delete mainBBox;
}
} // namespace Tyra
@@ -0,0 +1,84 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include <string>
#include "renderer/3d/pipeline/std/core/bag/stdpip_bag.hpp"
namespace Tyra {
StdpipBag::StdpipBag() {
info = nullptr;
color = nullptr;
texture = nullptr;
lighting = nullptr;
}
StdpipBag::~StdpipBag() {}
StdpipBagPackagesBBox StdpipBag::calculateBbox(const u32& maxVertCount) {
TYRA_ASSERT(vertices != nullptr, "Vertices are required to calculate bbox");
TYRA_ASSERT(count > 0, "Count must be greater than 0 to calculate bbox");
return StdpipBagPackagesBBox(vertices, count, maxVertCount);
}
void StdpipBag::print() const {
auto text = getPrint(nullptr);
printf("%s\n", text.c_str());
}
void StdpipBag::print(const char* name) const {
auto text = getPrint(name);
printf("%s\n", text.c_str());
}
std::string StdpipBag::getPrint(const char* name) const {
std::stringstream res;
if (name) {
res << name << "(";
} else {
res << "StdpipBag(";
}
res << std::fixed << std::setprecision(4);
res << std::endl;
res << "Count: " << count << ", " << std::endl;
res << "Vertices present: " << (vertices != nullptr ? "Yes" : "No") << ", "
<< std::endl;
res << "Info present: " << (info != nullptr ? "Yes" : "No") << ", "
<< std::endl;
res << "Color present: " << (color != nullptr ? "Yes" : "No") << ", "
<< std::endl;
res << "Texture present: " << (texture != nullptr ? "Yes" : "No") << ", "
<< std::endl;
res << "Lighting present: " << (lighting != nullptr ? "Yes" : "No") << ", "
<< std::endl;
res << "Model matrix: " << info->model->getPrint() << ", " << std::endl;
if (color->single) {
res << "Color single: " << color->single->getPrint() << ", " << std::endl;
} else {
res << "Color many: " << color->many->getPrint() << ", " << std::endl;
}
if (texture) {
res << "Texture coords present: "
<< (texture->coordinates != nullptr ? "Yes" : "No") << ", "
<< std::endl;
res << "Texture: " << texture->texture->getPrint() << ", " << std::endl;
}
if (lighting) {
res << "Lighting normals present: " << (lighting->normals ? "Yes" : "No")
<< ", " << std::endl;
res << "Lighting matrix: " << lighting->lightMatrix->getPrint() << ", "
<< std::endl;
}
res << ")";
return res.str();
}
} // namespace Tyra
@@ -0,0 +1,22 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/std/core/bag/stdpip_color_bag.hpp"
namespace Tyra {
StdpipColorBag::StdpipColorBag() {
single = nullptr;
many = nullptr;
}
StdpipColorBag::~StdpipColorBag() {}
} // namespace Tyra
@@ -0,0 +1,24 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/std/core/bag/stdpip_info_bag.hpp"
namespace Tyra {
StdpipInfoBag::StdpipInfoBag() {
shadingType = StdpipShadingFlat;
blendingEnabled = true;
antiAliasingEnabled = false;
model = nullptr;
}
StdpipInfoBag::~StdpipInfoBag() {}
} // namespace Tyra
@@ -0,0 +1,122 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "debug/debug.hpp"
#include "renderer/3d/pipeline/std/core/bag/stdpip_lighting_bag.hpp"
namespace Tyra {
StdpipLightingBag::StdpipLightingBag(const bool& manual) {
isAllocated = false;
mode = Auto;
normals = nullptr;
lightMatrix = nullptr;
lightColors = nullptr;
lightDirections = nullptr;
if (manual) {
mode = Manual;
} else {
allocate();
}
}
StdpipLightingBag::~StdpipLightingBag() { deallocate(); }
void StdpipLightingBag::setAmbientColor(const Color& color) {
TYRA_ASSERT(mode != Manual, "Ambient color cannot be set in manual mode");
lightColors[3].set(reinterpret_cast<const Vec4&>(color));
}
void StdpipLightingBag::setDirectionalLightColors(Color* colors,
const u8& count) {
for (u8 i = 0; i < count; i++) setDirectionalLightColor(colors[i], i);
}
void StdpipLightingBag::setDirectionalLightDirections(Vec4* directions,
const u8& count) {
for (u8 i = 0; i < count; i++) setDirectionalLightDirection(directions[i], i);
}
void StdpipLightingBag::setDirectionalLightColor(const Color& color,
const u8& index) {
TYRA_ASSERT(mode != Manual,
"Directional lights cannot be set in manual mode");
TYRA_ASSERT(index < 3, "There are max 3 directional lights");
lightColors[index].set(reinterpret_cast<const Vec4&>(color));
}
void StdpipLightingBag::setDirectionalLightDirection(const Vec4& direction,
const u8& index) {
TYRA_ASSERT(mode != Manual,
"Directional lights cannot be set in manual mode");
TYRA_ASSERT(index < 3, "There are max 3 directional lights");
lightDirections[index].set(direction);
}
void StdpipLightingBag::setLightsManually(Vec4* colors, Vec4* directions) {
deallocate();
lightColors = colors;
lightDirections = directions;
mode = Manual;
}
void StdpipLightingBag::disableManualMode() {
allocate();
mode = Auto;
}
void StdpipLightingBag::allocate() {
if (isAllocated) return;
lightColors = new Vec4[4];
lightDirections = new Vec4[3];
for (u8 i = 0; i < 3; i++) {
lightColors[i].set(0.0F, 0.0F, 0.0F, 1.0F);
}
lightColors[3].set(.5F, .5F, .5F, 1.0F); // Ambient
for (u8 i = 0; i < 3; i++) {
lightDirections[i].set(1.0F, 1.0F, 1.0F, 1.0F);
}
isAllocated = true;
}
void StdpipLightingBag::deallocate() {
if (!isAllocated) return;
forceDeallocate();
}
void StdpipLightingBag::forceDeallocate() {
forceDeallocateColors();
forceDeallocateDirections();
isAllocated = false;
}
void StdpipLightingBag::forceDeallocateColors() {
if (lightColors != nullptr) {
delete[] lightColors;
lightColors = nullptr;
}
}
void StdpipLightingBag::forceDeallocateDirections() {
if (lightDirections != nullptr) {
delete[] lightDirections;
lightDirections = nullptr;
}
}
} // namespace Tyra
@@ -0,0 +1,22 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/std/core/bag/stdpip_texture_bag.hpp"
namespace Tyra {
StdpipTextureBag::StdpipTextureBag() {
coordinates = nullptr;
texture = nullptr;
}
StdpipTextureBag::~StdpipTextureBag() {}
} // namespace Tyra
@@ -0,0 +1,125 @@
; ______ ____ ___
; | \/ ____| |___|
; | | | \ | |
;---------------------------------------------------------------
; Copyright 2022, tyra - https://github.com/h4570/tyra
; Licenced under Apache License 2.0
; Sandro Sobczyński <sandro.sobczynski@gmail.com>
;
;---------------------------------------------------------------
; Triangle list
; AsIs = NO TRANSFORM
; Colors
;---------------------------------------------------------------
.syntax new
.name StdpipVU1As_Is_C
.vu
.init_vf_all
.init_vi_all
#include "src/renderer/core/paths/path1/programs/vcl_sml.i"
#include "src/renderer/core/paths/path1/programs/tyra_macros.i"
#include "inc/renderer/3d/pipeline/std/core/path1/programs/stdpip_vu1_shared_defines.h"
#define RGBA_STORE_OFFSET 0
#define XYZ2_STORE_OFFSET 1
--enter
--endenter
#vuprog StdpipVU1AsIsC
LoadTyraStaticData{ gifSetTag }
LoadTyraSingleColor{ singleColor, singleColorEnabled, VU1_SINGLE_COLOR_ADDR, VU1_OPTIONS_ADDR }
LoadTyraTags{ lodGifTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_CLUT_ADDR }
begin:
xtop buffer
LoadTyraBufferTags{ scale, primTag, buffer }
iaddiu vertexData, buffer, VU1_VERT_DATA_ADDR
ilw.w vertexCount, 0(buffer)
iadd colorData, vertexData, vertexCount
iblez singleColorEnabled, setDestAddrMultiColor
iadd kickAddress, vertexData, vertexCount
b setDestAddr
setDestAddrMultiColor:
iadd kickAddress, colorData, vertexCount
setDestAddr:
iaddiu destAddress, kickAddress, 0
StoreTyraGifTags{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, destAddress }
;--- Loop
iadd vertexCounter, buffer, vertexCount
vertexLoop:
iblez singleColorEnabled, multiColor
;--- Load vertices single color
add color1, vf00, singleColor
add color2, vf00, singleColor
add color3, vf00, singleColor
b processing
multiColor:
;--- Load vertices colors
lq color1, (colorData)
lq color2, 1(colorData)
lq color3, 2(colorData)
processing:
;--- Load vertex1
lq.xyz vertex1, (vertexData)
;--- Load vertex2
lq.xyz vertex2, 1(vertexData)
;--- Load vertex3
lq.xyz vertex3, 2(vertexData)
;--- Calculate vertex1
ScaleVertexToGSFormat{ scale, vertex1 }
FixColor{ color1 }
;--- Calculate vertex2
ScaleVertexToGSFormat{ scale, vertex2 }
FixColor{ color2 }
;--- Calculate vertex3
ScaleVertexToGSFormat{ scale, vertex3 }
FixColor{ color3 }
;--- Store vertex1
sq color1, RGBA_STORE_OFFSET(destAddress)
sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress)
;--- Store vertex2
sq color2, RGBA_STORE_OFFSET+2(destAddress)
sq.xyz vertex2, XYZ2_STORE_OFFSET+2(destAddress)
;--- Store vertex3
sq color3, RGBA_STORE_OFFSET+4(destAddress)
sq.xyz vertex3, XYZ2_STORE_OFFSET+4(destAddress)
;-------------------------------
iaddiu vertexData, vertexData, 3
iaddiu colorData, colorData, 3
iaddiu destAddress, destAddress, 6
;--- Fix loop
iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter
ibne vertexCounter, buffer, vertexLoop ; and repeat if needed
xgkick kickAddress ; dispatch to the GS rasterizer.
--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it...
--cont
b begin
#endvuprog
--exit
--endexit
@@ -0,0 +1,47 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "debug/debug.hpp"
#include "renderer/3d/pipeline/std/core/path1/programs/as_is/stdpip_as_is_c_vu1_program.hpp"
extern u32 StdpipVU1As_Is_C_CodeStart __attribute__((section(".vudata")));
extern u32 StdpipVU1As_Is_C_CodeEnd __attribute__((section(".vudata")));
namespace Tyra {
StdpipAsIsCVU1Program::StdpipAsIsCVU1Program()
: StdpipVU1Program(StdpipAsIsColor, &StdpipVU1As_Is_C_CodeStart,
&StdpipVU1As_Is_C_CodeEnd,
((u64)GIF_REG_RGBAQ) << 0 | ((u64)GIF_REG_XYZ2) << 4, 2,
2) {}
StdpipAsIsCVU1Program::~StdpipAsIsCVU1Program() {}
std::string StdpipAsIsCVU1Program::getStringName() const {
return std::string("As is - C");
}
void StdpipAsIsCVU1Program::addProgramQBufferDataToPacket(
packet2_t* packet, StdpipQBuffer* qbuffer) const {
u32 addr = VU1_VERT_DATA_ADDR;
// Add vertices
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices,
qbuffer->size, true);
// Add colors
if (qbuffer->bag->color->single == nullptr) {
addr += qbuffer->size;
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors,
qbuffer->size, true);
}
}
} // namespace Tyra
@@ -0,0 +1,111 @@
; ______ ____ ___
; | \/ ____| |___|
; | | | \ | |
;---------------------------------------------------------------
; Copyright 2022, tyra - https://github.com/h4570/tyra
; Licenced under Apache License 2.0
; Sandro Sobczyński <sandro.sobczynski@gmail.com>
;
;---------------------------------------------------------------
; Triangle list
; AsIs = NO TRANSFORM
; Directional lights
;---------------------------------------------------------------
.syntax new
.name StdpipVU1As_Is_D
.vu
.init_vf_all
.init_vi_all
#include "src/renderer/core/paths/path1/programs/vcl_sml.i"
#include "src/renderer/core/paths/path1/programs/tyra_macros.i"
#include "inc/renderer/3d/pipeline/std/core/path1/programs/stdpip_vu1_shared_defines.h"
#define RGBA_STORE_OFFSET 0
#define XYZ2_STORE_OFFSET 1
--enter
--endenter
#vuprog StdpipVU1AsIsD
LoadTyraStaticData{ gifSetTag }
LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR }
LoadTyraTags{ lodGifTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_CLUT_ADDR }
begin:
xtop buffer
LoadTyraBufferTags{ scale, primTag, buffer }
iaddiu vertexData, buffer, VU1_VERT_DATA_ADDR
ilw.w vertexCount, 0(buffer)
iadd normalData, vertexData, vertexCount
iadd kickAddress, normalData, vertexCount
iadd destAddress, normalData, vertexCount
StoreTyraGifTags{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, destAddress }
;--- Loop
iadd vertexCounter, buffer, vertexCount
vertexLoop:
;--- Load vertex1
lq.xyz vertex1, (vertexData)
lq.xyz normal1, (normalData)
;--- Load vertex2
lq.xyz vertex2, 1(vertexData)
lq.xyz normal2, 1(normalData)
;--- Load vertex3
lq.xyz vertex3, 2(vertexData)
lq.xyz normal3, 2(normalData)
;--- Calculate vertex1
ScaleVertexToGSFormat{ scale, vertex1 }
CalculateTyraDirectionalLights{ outputColor1, normal1, lightDirections, lightColors, lightMatrix, ambientColor }
FixColor{ outputColor1 }
;--- Calculate vertex2
ScaleVertexToGSFormat{ scale, vertex2 }
CalculateTyraDirectionalLights{ outputColor2, normal2, lightDirections, lightColors, lightMatrix, ambientColor }
FixColor{ outputColor2 }
;--- Calculate vertex3
ScaleVertexToGSFormat{ scale, vertex3 }
CalculateTyraDirectionalLights{ outputColor3, normal3, lightDirections, lightColors, lightMatrix, ambientColor }
FixColor{ outputColor3 }
;--- Store vertex1
sq outputColor1, RGBA_STORE_OFFSET(destAddress)
sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress)
;--- Store vertex2
sq outputColor2, RGBA_STORE_OFFSET+2(destAddress)
sq.xyz vertex2, XYZ2_STORE_OFFSET+2(destAddress)
;--- Store vertex3
sq outputColor3, RGBA_STORE_OFFSET+4(destAddress)
sq.xyz vertex3, XYZ2_STORE_OFFSET+4(destAddress)
;-------------------------------
iaddiu vertexData, vertexData, 3
iaddiu normalData, normalData, 3
iaddiu destAddress, destAddress, 6
;--- Fix loop
iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter
ibne vertexCounter, buffer, vertexLoop ; and repeat if needed
xgkick kickAddress ; dispatch to the GS rasterizer.
--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it...
--cont
b begin
#endvuprog
--exit
--endexit
@@ -0,0 +1,52 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "debug/debug.hpp"
#include "renderer/3d/pipeline/std/core/path1/programs/as_is/stdpip_as_is_d_vu1_program.hpp"
extern u32 StdpipVU1As_Is_D_CodeStart __attribute__((section(".vudata")));
extern u32 StdpipVU1As_Is_D_CodeEnd __attribute__((section(".vudata")));
namespace Tyra {
StdpipAsIsDVU1Program::StdpipAsIsDVU1Program()
: StdpipVU1Program(StdpipAsIsDirLights, &StdpipVU1As_Is_D_CodeStart,
&StdpipVU1As_Is_D_CodeEnd,
((u64)GIF_REG_RGBAQ) << 0 | ((u64)GIF_REG_XYZ2) << 4, 2,
3) {}
StdpipAsIsDVU1Program::~StdpipAsIsDVU1Program() {}
std::string StdpipAsIsDVU1Program::getStringName() const {
return std::string("As is - LC");
}
void StdpipAsIsDVU1Program::addProgramQBufferDataToPacket(
packet2_t* packet, StdpipQBuffer* qbuffer) const {
u32 addr = VU1_VERT_DATA_ADDR;
// Add vertices
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices,
qbuffer->size, true);
addr += qbuffer->size;
// Add normal
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->normals,
qbuffer->size, true);
// Add colors
if (qbuffer->bag->color->single == nullptr) {
addr += qbuffer->size;
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors,
qbuffer->size, true);
}
}
} // namespace Tyra
@@ -0,0 +1,140 @@
; ______ ____ ___
; | \/ ____| |___|
; | | | \ | |
;---------------------------------------------------------------
; Copyright 2022, tyra - https://github.com/h4570/tyra
; Licenced under Apache License 2.0
; Sandro Sobczyński <sandro.sobczynski@gmail.com>
;
;---------------------------------------------------------------
; Triangle list
; AsIs = NO TRANSFORM
; Texture, colors
;---------------------------------------------------------------
.syntax new
.name StdpipVU1As_Is_TC
.vu
.init_vf_all
.init_vi_all
#include "src/renderer/core/paths/path1/programs/vcl_sml.i"
#include "src/renderer/core/paths/path1/programs/tyra_macros.i"
#include "inc/renderer/3d/pipeline/std/core/path1/programs/stdpip_vu1_shared_defines.h"
#define STQ_STORE_OFFSET 0
#define RGBA_STORE_OFFSET 1
#define XYZ2_STORE_OFFSET 2
--enter
--endenter
#vuprog StdpipVU1AsIsTC
LoadTyraStaticData{ gifSetTag }
LoadTyraSingleColor{ singleColor, singleColorEnabled, VU1_SINGLE_COLOR_ADDR, VU1_OPTIONS_ADDR }
LoadTyraTags{ lodGifTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_CLUT_ADDR }
begin:
xtop buffer
LoadTyraBufferTags{ scale, primTag, buffer }
iaddiu vertexData, buffer, VU1_VERT_DATA_ADDR
ilw.w vertexCount, 0(buffer)
iadd stqData, vertexData, vertexCount
iadd colorData, stqData, vertexCount
iblez singleColorEnabled, setDestAddrMultiColor
iadd kickAddress, stqData, vertexCount
b setDestAddr
setDestAddrMultiColor:
iadd kickAddress, colorData, vertexCount
setDestAddr:
iaddiu destAddress, kickAddress, 0
StoreTyraGifTags{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, destAddress }
;--- Loop
iadd vertexCounter, buffer, vertexCount
vertexLoop:
iblez singleColorEnabled, multiColor
;--- Load vertices single color
add color1, vf00, singleColor
add color2, vf00, singleColor
add color3, vf00, singleColor
b processing
multiColor:
;--- Load vertices colors
lq color1, (colorData)
lq color2, 1(colorData)
lq color3, 2(colorData)
processing:
;--- Load vertex1
lq vertex1, (vertexData)
lq stq1, (stqData)
;--- Load vertex2
lq vertex2, 1(vertexData)
lq stq2, 1(stqData)
;--- Load vertex3
lq vertex3, 2(vertexData)
lq stq3, 2(stqData)
;--- Calculate vertex1
ScaleVertexToGSFormat{ scale, vertex1 }
div q, vf00[w], vertex1[w]
PerformTexturePerspectiveCorrection{ outputStq1, stq1 }
FixColor{ color1 }
;--- Calculate vertex2
ScaleVertexToGSFormat{ scale, vertex2 }
div q, vf00[w], vertex2[w]
PerformTexturePerspectiveCorrection{ outputStq2, stq2 }
FixColor{ color2 }
;--- Calculate vertex3
ScaleVertexToGSFormat{ scale, vertex3 }
div q, vf00[w], vertex3[w]
PerformTexturePerspectiveCorrection{ outputStq3, stq3 }
FixColor{ color3 }
;--- Store vertex1
sq outputStq1, STQ_STORE_OFFSET(destAddress)
sq color1, RGBA_STORE_OFFSET(destAddress)
sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress)
;--- Store vertex2
sq outputStq2, STQ_STORE_OFFSET+3(destAddress)
sq color2, RGBA_STORE_OFFSET+3(destAddress)
sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress)
;--- Store vertex3
sq outputStq3, STQ_STORE_OFFSET+6(destAddress)
sq color3, RGBA_STORE_OFFSET+6(destAddress)
sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress)
;-------------------------------
iaddiu vertexData, vertexData, 3
iaddiu stqData, stqData, 3
iaddiu colorData, colorData, 3
iaddiu destAddress, destAddress, 9
;--- Fix loop
iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter
ibne vertexCounter, buffer, vertexLoop ; and repeat if needed
xgkick kickAddress ; dispatch to the GS rasterizer.
--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it...
--cont
b begin
#endvuprog
--exit
--endexit
@@ -0,0 +1,53 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "debug/debug.hpp"
#include "renderer/3d/pipeline/std/core/path1/programs/as_is/stdpip_as_is_tc_vu1_program.hpp"
extern u32 StdpipVU1As_Is_TC_CodeStart __attribute__((section(".vudata")));
extern u32 StdpipVU1As_Is_TC_CodeEnd __attribute__((section(".vudata")));
namespace Tyra {
StdpipAsIsTCVU1Program::StdpipAsIsTCVU1Program()
: StdpipVU1Program(StdpipAsIsTextureColor, &StdpipVU1As_Is_TC_CodeStart,
&StdpipVU1As_Is_TC_CodeEnd,
((u64)GIF_REG_ST) << 0 | ((u64)GIF_REG_RGBAQ) << 4 |
((u64)GIF_REG_XYZ2) << 8,
3, 3) {}
StdpipAsIsTCVU1Program::~StdpipAsIsTCVU1Program() {}
std::string StdpipAsIsTCVU1Program::getStringName() const {
return std::string("As is - TC");
}
void StdpipAsIsTCVU1Program::addProgramQBufferDataToPacket(
packet2_t* packet, StdpipQBuffer* qbuffer) const {
u32 addr = VU1_VERT_DATA_ADDR;
// Add vertices
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices,
qbuffer->size, true);
addr += qbuffer->size;
// Add sts
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->sts, qbuffer->size,
true);
// Add colors
if (qbuffer->bag->color->single == nullptr) {
addr += qbuffer->size;
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors,
qbuffer->size, true);
}
}
} // namespace Tyra
@@ -0,0 +1,126 @@
; ______ ____ ___
; | \/ ____| |___|
; | | | \ | |
;---------------------------------------------------------------
; Copyright 2022, tyra - https://github.com/h4570/tyra
; Licenced under Apache License 2.0
; Sandro Sobczyński <sandro.sobczynski@gmail.com>
;
;---------------------------------------------------------------
; Triangle list
; AsIs = NO TRANSFORM
; Texture, directional lights
;---------------------------------------------------------------
.syntax new
.name StdpipVU1As_Is_TD
.vu
.init_vf_all
.init_vi_all
#include "src/renderer/core/paths/path1/programs/vcl_sml.i"
#include "src/renderer/core/paths/path1/programs/tyra_macros.i"
#include "inc/renderer/3d/pipeline/std/core/path1/programs/stdpip_vu1_shared_defines.h"
#define STQ_STORE_OFFSET 0
#define RGBA_STORE_OFFSET 1
#define XYZ2_STORE_OFFSET 2
--enter
--endenter
#vuprog StdpipVU1AsIsTD
LoadTyraStaticData{ gifSetTag }
LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR }
LoadTyraTags{ lodGifTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_CLUT_ADDR }
begin:
xtop buffer
LoadTyraBufferTags{ scale, primTag, buffer }
iaddiu vertexData, buffer, VU1_VERT_DATA_ADDR
ilw.w vertexCount, 0(buffer)
iadd stqData, vertexData, vertexCount
iadd normalData, stqData, vertexCount
iadd kickAddress, normalData, vertexCount
iadd destAddress, normalData, vertexCount
StoreTyraGifTags{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, destAddress }
;--- Loop
iadd vertexCounter, buffer, vertexCount
vertexLoop:
;--- Load vertex1
lq vertex1, (vertexData)
lq stq1, (stqData)
lq.xyz normal1, (normalData)
;--- Load vertex2
lq vertex2, 1(vertexData)
lq stq2, 1(stqData)
lq.xyz normal2, 1(normalData)
;--- Load vertex3
lq vertex3, 2(vertexData)
lq stq3, 2(stqData)
lq.xyz normal3, 2(normalData)
;--- Calculate vertex1
ScaleVertexToGSFormat{ scale, vertex1 }
div q, vf00[w], vertex1[w]
PerformTexturePerspectiveCorrection{ outputStq1, stq1 }
CalculateTyraDirectionalLights{ outputColor1, normal1, lightDirections, lightColors, lightMatrix, ambientColor }
FixColor{ outputColor1 }
;--- Calculate vertex2
ScaleVertexToGSFormat{ scale, vertex2 }
div q, vf00[w], vertex2[w]
PerformTexturePerspectiveCorrection{ outputStq2, stq2 }
CalculateTyraDirectionalLights{ outputColor2, normal2, lightDirections, lightColors, lightMatrix, ambientColor }
FixColor{ outputColor2 }
;--- Calculate vertex3
ScaleVertexToGSFormat{ scale, vertex3 }
div q, vf00[w], vertex3[w]
PerformTexturePerspectiveCorrection{ outputStq3, stq3 }
CalculateTyraDirectionalLights{ outputColor3, normal3, lightDirections, lightColors, lightMatrix, ambientColor }
FixColor{ outputColor3 }
;--- Store vertex1
sq outputStq1, STQ_STORE_OFFSET(destAddress)
sq outputColor1, RGBA_STORE_OFFSET(destAddress)
sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress)
;--- Store vertex2
sq outputStq2, STQ_STORE_OFFSET+3(destAddress)
sq outputColor2, RGBA_STORE_OFFSET+3(destAddress)
sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress)
;--- Store vertex3
sq outputStq3, STQ_STORE_OFFSET+6(destAddress)
sq outputColor3, RGBA_STORE_OFFSET+6(destAddress)
sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress)
;-------------------------------
iaddiu vertexData, vertexData, 3
iaddiu stqData, stqData, 3
iaddiu normalData, normalData, 3
iaddiu destAddress, destAddress, 9
;--- Fix loop
iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter
ibne vertexCounter, buffer, vertexLoop ; and repeat if needed
xgkick kickAddress ; dispatch to the GS rasterizer.
--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it...
--cont
b begin
#endvuprog
--exit
--endexit
@@ -0,0 +1,58 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "debug/debug.hpp"
#include "renderer/3d/pipeline/std/core/path1/programs/as_is/stdpip_as_is_td_vu1_program.hpp"
extern u32 StdpipVU1As_Is_TD_CodeStart __attribute__((section(".vudata")));
extern u32 StdpipVU1As_Is_TD_CodeEnd __attribute__((section(".vudata")));
namespace Tyra {
StdpipAsIsTDVU1Program::StdpipAsIsTDVU1Program()
: StdpipVU1Program(StdpipAsIsTextureDirLights, &StdpipVU1As_Is_TD_CodeStart,
&StdpipVU1As_Is_TD_CodeEnd,
((u64)GIF_REG_ST) << 0 | ((u64)GIF_REG_RGBAQ) << 4 |
((u64)GIF_REG_XYZ2) << 8,
3, 4) {}
StdpipAsIsTDVU1Program::~StdpipAsIsTDVU1Program() {}
std::string StdpipAsIsTDVU1Program::getStringName() const {
return std::string("As is - LTC");
}
void StdpipAsIsTDVU1Program::addProgramQBufferDataToPacket(
packet2_t* packet, StdpipQBuffer* qbuffer) const {
u32 addr = VU1_VERT_DATA_ADDR;
// Add vertices
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices,
qbuffer->size, true);
addr += qbuffer->size;
// Add sts
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->sts, qbuffer->size,
true);
addr += qbuffer->size;
// Add normal
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->normals,
qbuffer->size, true);
// Add colors
if (qbuffer->bag->color->single == nullptr) {
addr += qbuffer->size;
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors,
qbuffer->size, true);
}
}
} // namespace Tyra
@@ -0,0 +1,136 @@
; ______ ____ ___
; | \/ ____| |___|
; | | | \ | |
;---------------------------------------------------------------
; Copyright 2022, tyra - https://github.com/h4570/tyra
; Licenced under Apache License 2.0
; Sandro Sobczyński <sandro.sobczynski@gmail.com>
;
;---------------------------------------------------------------
; Triangle list
; Cull = Standard PS2 way. clipw polys are culled.
; Volors
;---------------------------------------------------------------
.syntax new
.name StdpipVU1Cull_C
.vu
.init_vf_all
.init_vi_all
#include "src/renderer/core/paths/path1/programs/vcl_sml.i"
#include "src/renderer/core/paths/path1/programs/tyra_macros.i"
#include "inc/renderer/3d/pipeline/std/core/path1/programs/stdpip_vu1_shared_defines.h"
#define RGBA_STORE_OFFSET 0
#define XYZ2_STORE_OFFSET 1
--enter
--endenter
#vuprog StdpipVU1CullC
ResetClipFlags{ }
LoadTyraStaticData{ gifSetTag }
MatrixLoad{ mvp, VU1_MVP_MATRIX_ADDR, vi00 }
LoadTyraSingleColor{ singleColor, singleColorEnabled, VU1_SINGLE_COLOR_ADDR, VU1_OPTIONS_ADDR }
LoadTyraTags{ lodGifTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_CLUT_ADDR }
begin:
xtop buffer
LoadTyraBufferTags{ scale, primTag, buffer }
iaddiu vertexData, buffer, VU1_VERT_DATA_ADDR
ilw.w vertexCount, 0(buffer)
iadd colorData, vertexData, vertexCount
iblez singleColorEnabled, setDestAddrMultiColor
iadd kickAddress, vertexData, vertexCount
b setDestAddr
setDestAddrMultiColor:
iadd kickAddress, colorData, vertexCount
setDestAddr:
iaddiu destAddress, kickAddress, 0
StoreTyraGifTags{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, destAddress }
;--- Loop
iadd vertexCounter, buffer, vertexCount
vertexLoop:
iblez singleColorEnabled, multiColor
;--- Load vertices single color
add color1, vf00, singleColor
add color2, vf00, singleColor
add color3, vf00, singleColor
b processing
multiColor:
;--- Load vertices colors
lq color1, (colorData)
lq color2, 1(colorData)
lq color3, 2(colorData)
processing:
;--- Load vertex1
lq vertex1, (vertexData)
;--- Load vertex2
lq vertex2, 1(vertexData)
;--- Load vertex3
lq vertex3, 2(vertexData)
;--- Calculate vertex1
MatrixMultiplyVertex{ vertex1, mvp, vertex1 }
PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET }
VertexPersCorr{ vertex1, vertex1 }
ScaleVertexToGSFormat{ scale, vertex1 }
FixColor{ color1 }
;--- Calculate vertex2
MatrixMultiplyVertex{ vertex2, mvp, vertex2 }
PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET+2 }
VertexPersCorr{ vertex2, vertex2 }
ScaleVertexToGSFormat{ scale, vertex2 }
FixColor{ color2 }
;--- Calculate vertex3
MatrixMultiplyVertex{ vertex3, mvp, vertex3 }
PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET+4 }
VertexPersCorr{ vertex3, vertex3 }
ScaleVertexToGSFormat{ scale, vertex3 }
FixColor{ color3 }
;--- Store vertex1
sq color1, RGBA_STORE_OFFSET(destAddress)
sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress)
;--- Store vertex2
sq color2, RGBA_STORE_OFFSET+2(destAddress)
sq.xyz vertex2, XYZ2_STORE_OFFSET+2(destAddress)
;--- Store vertex3
sq color3, RGBA_STORE_OFFSET+4(destAddress)
sq.xyz vertex3, XYZ2_STORE_OFFSET+4(destAddress)
;-------------------------------
iaddiu vertexData, vertexData, 3
iaddiu colorData, colorData, 3
iaddiu destAddress, destAddress, 6
;--- Fix loop
iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter
ibne vertexCounter, buffer, vertexLoop ; and repeat if needed
xgkick kickAddress ; dispatch to the GS rasterizer.
--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it...
--cont
b begin
#endvuprog
--exit
--endexit
@@ -0,0 +1,46 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "debug/debug.hpp"
#include "renderer/3d/pipeline/std/core/path1/programs/cull/stdpip_cull_c_vu1_program.hpp"
extern u32 StdpipVU1Cull_C_CodeStart __attribute__((section(".vudata")));
extern u32 StdpipVU1Cull_C_CodeEnd __attribute__((section(".vudata")));
namespace Tyra {
StdpipCullCVU1Program::StdpipCullCVU1Program()
: StdpipVU1Program(
StdpipCullColor, &StdpipVU1Cull_C_CodeStart, &StdpipVU1Cull_C_CodeEnd,
((u64)GIF_REG_RGBAQ) << 0 | ((u64)GIF_REG_XYZ2) << 4, 2, 2) {}
StdpipCullCVU1Program::~StdpipCullCVU1Program() {}
std::string StdpipCullCVU1Program::getStringName() const {
return std::string("Cull - C");
}
void StdpipCullCVU1Program::addProgramQBufferDataToPacket(
packet2_t* packet, StdpipQBuffer* qbuffer) const {
u32 addr = VU1_VERT_DATA_ADDR;
// Add vertices
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices,
qbuffer->size, true);
// Add colors
if (qbuffer->bag->color->single == nullptr) {
addr += qbuffer->size;
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors,
qbuffer->size, true);
}
}
} // namespace Tyra
@@ -0,0 +1,122 @@
; ______ ____ ___
; | \/ ____| |___|
; | | | \ | |
;---------------------------------------------------------------
; Copyright 2022, tyra - https://github.com/h4570/tyra
; Licenced under Apache License 2.0
; Sandro Sobczyński <sandro.sobczynski@gmail.com>
;
;---------------------------------------------------------------
; Triangle list
; Cull = Standard PS2 way. clipw polys are culled.
; Directional lights
;---------------------------------------------------------------
.syntax new
.name StdpipVU1Cull_D
.vu
.init_vf_all
.init_vi_all
#include "src/renderer/core/paths/path1/programs/vcl_sml.i"
#include "src/renderer/core/paths/path1/programs/tyra_macros.i"
#include "inc/renderer/3d/pipeline/std/core/path1/programs/stdpip_vu1_shared_defines.h"
#define RGBA_STORE_OFFSET 0
#define XYZ2_STORE_OFFSET 1
--enter
--endenter
#vuprog StdpipVU1CullD
ResetClipFlags{ }
LoadTyraStaticData{ gifSetTag }
MatrixLoad{ mvp, VU1_MVP_MATRIX_ADDR, vi00 }
LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR }
LoadTyraTags{ lodGifTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_CLUT_ADDR }
begin:
xtop buffer
LoadTyraBufferTags{ scale, primTag, buffer }
iaddiu vertexData, buffer, VU1_VERT_DATA_ADDR
ilw.w vertexCount, 0(buffer)
iadd normalData, vertexData, vertexCount
iadd kickAddress, normalData, vertexCount
iadd destAddress, normalData, vertexCount
StoreTyraGifTags{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, destAddress }
;--- Loop
iadd vertexCounter, buffer, vertexCount
vertexLoop:
;--- Load vertex1
lq vertex1, (vertexData)
lq.xyz normal1, (normalData)
;--- Load vertex2
lq vertex2, 1(vertexData)
lq.xyz normal2, 1(normalData)
;--- Load vertex3
lq vertex3, 2(vertexData)
lq.xyz normal3, 2(normalData)
;--- Calculate vertex1
MatrixMultiplyVertex{ vertex1, mvp, vertex1 }
PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET }
VertexPersCorr{ vertex1, vertex1 }
ScaleVertexToGSFormat{ scale, vertex1 }
CalculateTyraDirectionalLights{ outputColor1, normal1, lightDirections, lightColors, lightMatrix, ambientColor }
FixColor{ outputColor1 }
;--- Calculate vertex2
MatrixMultiplyVertex{ vertex2, mvp, vertex2 }
PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET+2 }
VertexPersCorr{ vertex2, vertex2 }
ScaleVertexToGSFormat{ scale, vertex2 }
CalculateTyraDirectionalLights{ outputColor2, normal2, lightDirections, lightColors, lightMatrix, ambientColor }
FixColor{ outputColor2 }
;--- Calculate vertex3
MatrixMultiplyVertex{ vertex3, mvp, vertex3 }
PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET+4 }
VertexPersCorr{ vertex3, vertex3 }
ScaleVertexToGSFormat{ scale, vertex3 }
CalculateTyraDirectionalLights{ outputColor3, normal3, lightDirections, lightColors, lightMatrix, ambientColor }
FixColor{ outputColor3 }
;--- Store vertex1
sq outputColor1, RGBA_STORE_OFFSET(destAddress)
sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress)
;--- Store vertex2
sq outputColor2, RGBA_STORE_OFFSET+2(destAddress)
sq.xyz vertex2, XYZ2_STORE_OFFSET+2(destAddress)
;--- Store vertex3
sq outputColor3, RGBA_STORE_OFFSET+4(destAddress)
sq.xyz vertex3, XYZ2_STORE_OFFSET+4(destAddress)
;-------------------------------
iaddiu vertexData, vertexData, 3
iaddiu normalData, normalData, 3
iaddiu destAddress, destAddress, 6
;--- Fix loop
iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter
ibne vertexCounter, buffer, vertexLoop ; and repeat if needed
xgkick kickAddress ; dispatch to the GS rasterizer.
--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it...
--cont
b begin
#endvuprog
--exit
--endexit
@@ -0,0 +1,52 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "debug/debug.hpp"
#include "renderer/3d/pipeline/std/core/path1/programs/cull/stdpip_cull_d_vu1_program.hpp"
extern u32 StdpipVU1Cull_D_CodeStart __attribute__((section(".vudata")));
extern u32 StdpipVU1Cull_D_CodeEnd __attribute__((section(".vudata")));
namespace Tyra {
StdpipCullDVU1Program::StdpipCullDVU1Program()
: StdpipVU1Program(StdpipCullDirLights, &StdpipVU1Cull_D_CodeStart,
&StdpipVU1Cull_D_CodeEnd,
((u64)GIF_REG_RGBAQ) << 0 | ((u64)GIF_REG_XYZ2) << 4, 2,
3) {}
StdpipCullDVU1Program::~StdpipCullDVU1Program() {}
std::string StdpipCullDVU1Program::getStringName() const {
return std::string("Cull - LC");
}
void StdpipCullDVU1Program::addProgramQBufferDataToPacket(
packet2_t* packet, StdpipQBuffer* qbuffer) const {
u32 addr = VU1_VERT_DATA_ADDR;
// Add vertices
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices,
qbuffer->size, true);
addr += qbuffer->size;
// Add normal
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->normals,
qbuffer->size, true);
// Add colors
if (qbuffer->bag->color->single == nullptr) {
addr += qbuffer->size;
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors,
qbuffer->size, true);
}
}
} // namespace Tyra
@@ -0,0 +1,148 @@
; ______ ____ ___
; | \/ ____| |___|
; | | | \ | |
;---------------------------------------------------------------
; Copyright 2022, tyra - https://github.com/h4570/tyra
; Licenced under Apache License 2.0
; Sandro Sobczyński <sandro.sobczynski@gmail.com>
;
;---------------------------------------------------------------
; Triangle list
; Cull = Standard PS2 way. clipw polys are culled.
; Lighting, texture, colors
;---------------------------------------------------------------
.syntax new
.name StdpipVU1Cull_TC
.vu
.init_vf_all
.init_vi_all
#include "src/renderer/core/paths/path1/programs/vcl_sml.i"
#include "src/renderer/core/paths/path1/programs/tyra_macros.i"
#include "inc/renderer/3d/pipeline/std/core/path1/programs/stdpip_vu1_shared_defines.h"
#define STQ_STORE_OFFSET 0
#define RGBA_STORE_OFFSET 1
#define XYZ2_STORE_OFFSET 2
--enter
--endenter
#vuprog StdpipVU1CullTC
ResetClipFlags{ }
LoadTyraStaticData{ gifSetTag }
MatrixLoad{ mvp, VU1_MVP_MATRIX_ADDR, vi00 }
LoadTyraSingleColor{ singleColor, singleColorEnabled, VU1_SINGLE_COLOR_ADDR, VU1_OPTIONS_ADDR }
LoadTyraTags{ lodGifTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_CLUT_ADDR }
begin:
xtop buffer
LoadTyraBufferTags{ scale, primTag, buffer }
iaddiu vertexData, buffer, VU1_VERT_DATA_ADDR
ilw.w vertexCount, 0(buffer)
iadd stqData, vertexData, vertexCount
iadd colorData, stqData, vertexCount
iblez singleColorEnabled, setDestAddrMultiColor
iadd kickAddress, stqData, vertexCount
b setDestAddr
setDestAddrMultiColor:
iadd kickAddress, colorData, vertexCount
setDestAddr:
iaddiu destAddress, kickAddress, 0
StoreTyraGifTags{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, destAddress }
;--- Loop
iadd vertexCounter, buffer, vertexCount
vertexLoop:
iblez singleColorEnabled, multiColor
;--- Load vertices single color
add color1, vf00, singleColor
add color2, vf00, singleColor
add color3, vf00, singleColor
b processing
multiColor:
;--- Load vertices colors
lq color1, (colorData)
lq color2, 1(colorData)
lq color3, 2(colorData)
processing:
;--- Load vertex1
lq vertex1, (vertexData)
lq stq1, (stqData)
;--- Load vertex2
lq vertex2, 1(vertexData)
lq stq2, 1(stqData)
;--- Load vertex3
lq vertex3, 2(vertexData)
lq stq3, 2(stqData)
;--- Calculate vertex1
MatrixMultiplyVertex{ vertex1, mvp, vertex1 }
PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET }
VertexPersCorr{ vertex1, vertex1 }
ScaleVertexToGSFormat{ scale, vertex1 }
PerformTexturePerspectiveCorrection{ outputStq1, stq1 }
FixColor{ color1 }
;--- Calculate vertex2
MatrixMultiplyVertex{ vertex2, mvp, vertex2 }
PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET+3 }
VertexPersCorr{ vertex2, vertex2 }
ScaleVertexToGSFormat{ scale, vertex2 }
PerformTexturePerspectiveCorrection{ outputStq2, stq2 }
FixColor{ color2 }
;--- Calculate vertex3
MatrixMultiplyVertex{ vertex3, mvp, vertex3 }
PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET+6 }
VertexPersCorr{ vertex3, vertex3 }
ScaleVertexToGSFormat{ scale, vertex3 }
PerformTexturePerspectiveCorrection{ outputStq3, stq3 }
FixColor{ color3 }
;--- Store vertex1
sq outputStq1, STQ_STORE_OFFSET(destAddress)
sq color1, RGBA_STORE_OFFSET(destAddress)
sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress)
;--- Store vertex2
sq outputStq2, STQ_STORE_OFFSET+3(destAddress)
sq color2, RGBA_STORE_OFFSET+3(destAddress)
sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress)
;--- Store vertex3
sq outputStq3, STQ_STORE_OFFSET+6(destAddress)
sq color3, RGBA_STORE_OFFSET+6(destAddress)
sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress)
;-------------------------------
iaddiu vertexData, vertexData, 3
iaddiu stqData, stqData, 3
iaddiu colorData, colorData, 3
iaddiu destAddress, destAddress, 9
;--- Fix loop
iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter
ibne vertexCounter, buffer, vertexLoop ; and repeat if needed
xgkick kickAddress ; dispatch to the GS rasterizer.
--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it...
--cont
b begin
#endvuprog
--exit
--endexit
@@ -0,0 +1,53 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "debug/debug.hpp"
#include "renderer/3d/pipeline/std/core/path1/programs/cull/stdpip_cull_tc_vu1_program.hpp"
extern u32 StdpipVU1Cull_TC_CodeStart __attribute__((section(".vudata")));
extern u32 StdpipVU1Cull_TC_CodeEnd __attribute__((section(".vudata")));
namespace Tyra {
StdpipCullTCVU1Program::StdpipCullTCVU1Program()
: StdpipVU1Program(StdpipCullTextureColor, &StdpipVU1Cull_TC_CodeStart,
&StdpipVU1Cull_TC_CodeEnd,
((u64)GIF_REG_ST) << 0 | ((u64)GIF_REG_RGBAQ) << 4 |
((u64)GIF_REG_XYZ2) << 8,
3, 3) {}
StdpipCullTCVU1Program::~StdpipCullTCVU1Program() {}
std::string StdpipCullTCVU1Program::getStringName() const {
return std::string("Cull - TC");
}
void StdpipCullTCVU1Program::addProgramQBufferDataToPacket(
packet2_t* packet, StdpipQBuffer* qbuffer) const {
u32 addr = VU1_VERT_DATA_ADDR;
// Add vertices
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices,
qbuffer->size, true);
addr += qbuffer->size;
// Add sts
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->sts, qbuffer->size,
true);
// Add colors
if (qbuffer->bag->color->single == nullptr) {
addr += qbuffer->size;
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors,
qbuffer->size, true);
}
}
} // namespace Tyra
@@ -0,0 +1,134 @@
; ______ ____ ___
; | \/ ____| |___|
; | | | \ | |
;---------------------------------------------------------------
; Copyright 2022, tyra - https://github.com/h4570/tyra
; Licenced under Apache License 2.0
; Sandro Sobczyński <sandro.sobczynski@gmail.com>
;
;---------------------------------------------------------------
; Triangle list
; Cull = Standard PS2 way. clipw polys are culled.
; Texture, directional lights
;---------------------------------------------------------------
.syntax new
.name StdpipVU1Cull_TD
.vu
.init_vf_all
.init_vi_all
#include "src/renderer/core/paths/path1/programs/vcl_sml.i"
#include "src/renderer/core/paths/path1/programs/tyra_macros.i"
#include "inc/renderer/3d/pipeline/std/core/path1/programs/stdpip_vu1_shared_defines.h"
#define STQ_STORE_OFFSET 0
#define RGBA_STORE_OFFSET 1
#define XYZ2_STORE_OFFSET 2
--enter
--endenter
#vuprog StdpipVU1CullTD
ResetClipFlags{ }
LoadTyraStaticData{ gifSetTag }
MatrixLoad{ mvp, VU1_MVP_MATRIX_ADDR, vi00 }
LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR }
LoadTyraTags{ lodGifTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_CLUT_ADDR }
begin:
xtop buffer
LoadTyraBufferTags{ scale, primTag, buffer }
iaddiu vertexData, buffer, VU1_VERT_DATA_ADDR
ilw.w vertexCount, 0(buffer)
iadd stqData, vertexData, vertexCount
iadd normalData, stqData, vertexCount
iadd kickAddress, normalData, vertexCount
iadd destAddress, normalData, vertexCount
StoreTyraGifTags{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, destAddress }
;--- Loop
iadd vertexCounter, buffer, vertexCount
vertexLoop:
;--- Load vertex1
lq vertex1, (vertexData)
lq stq1, (stqData)
lq.xyz normal1, (normalData)
;--- Load vertex2
lq vertex2, 1(vertexData)
lq stq2, 1(stqData)
lq.xyz normal2, 1(normalData)
;--- Load vertex3
lq vertex3, 2(vertexData)
lq stq3, 2(stqData)
lq.xyz normal3, 2(normalData)
;--- Calculate vertex1
MatrixMultiplyVertex{ vertex1, mvp, vertex1 }
PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET }
VertexPersCorr{ vertex1, vertex1 }
ScaleVertexToGSFormat{ scale, vertex1 }
PerformTexturePerspectiveCorrection{ outputStq1, stq1 }
CalculateTyraDirectionalLights{ outputColor1, normal1, lightDirections, lightColors, lightMatrix, ambientColor }
FixColor{ outputColor1 }
;--- Calculate vertex2
MatrixMultiplyVertex{ vertex2, mvp, vertex2 }
PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET+3 }
VertexPersCorr{ vertex2, vertex2 }
ScaleVertexToGSFormat{ scale, vertex2 }
PerformTexturePerspectiveCorrection{ outputStq2, stq2 }
CalculateTyraDirectionalLights{ outputColor2, normal2, lightDirections, lightColors, lightMatrix, ambientColor }
FixColor{ outputColor2 }
;--- Calculate vertex3
MatrixMultiplyVertex{ vertex3, mvp, vertex3 }
PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET+6 }
VertexPersCorr{ vertex3, vertex3 }
ScaleVertexToGSFormat{ scale, vertex3 }
PerformTexturePerspectiveCorrection{ outputStq3, stq3 }
CalculateTyraDirectionalLights{ outputColor3, normal3, lightDirections, lightColors, lightMatrix, ambientColor }
FixColor{ outputColor3 }
;--- Store vertex1
sq outputStq1, STQ_STORE_OFFSET(destAddress)
sq outputColor1, RGBA_STORE_OFFSET(destAddress)
sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress)
;--- Store vertex2
sq outputStq2, STQ_STORE_OFFSET+3(destAddress)
sq outputColor2, RGBA_STORE_OFFSET+3(destAddress)
sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress)
;--- Store vertex3
sq outputStq3, STQ_STORE_OFFSET+6(destAddress)
sq outputColor3, RGBA_STORE_OFFSET+6(destAddress)
sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress)
;-------------------------------
iaddiu vertexData, vertexData, 3
iaddiu stqData, stqData, 3
iaddiu normalData, normalData, 3
iaddiu destAddress, destAddress, 9
;--- Fix loop
iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter
ibne vertexCounter, buffer, vertexLoop ; and repeat if needed
xgkick kickAddress ; dispatch to the GS rasterizer.
--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it...
--cont
b begin
#endvuprog
--exit
--endexit
@@ -0,0 +1,58 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "debug/debug.hpp"
#include "renderer/3d/pipeline/std/core/path1/programs/cull/stdpip_cull_td_vu1_program.hpp"
extern u32 StdpipVU1Cull_TD_CodeStart __attribute__((section(".vudata")));
extern u32 StdpipVU1Cull_TD_CodeEnd __attribute__((section(".vudata")));
namespace Tyra {
StdpipCullTDVU1Program::StdpipCullTDVU1Program()
: StdpipVU1Program(StdpipCullTextureDirLights, &StdpipVU1Cull_TD_CodeStart,
&StdpipVU1Cull_TD_CodeEnd,
((u64)GIF_REG_ST) << 0 | ((u64)GIF_REG_RGBAQ) << 4 |
((u64)GIF_REG_XYZ2) << 8,
3, 4) {}
StdpipCullTDVU1Program::~StdpipCullTDVU1Program() {}
std::string StdpipCullTDVU1Program::getStringName() const {
return std::string("Cull - LTC");
}
void StdpipCullTDVU1Program::addProgramQBufferDataToPacket(
packet2_t* packet, StdpipQBuffer* qbuffer) const {
u32 addr = VU1_VERT_DATA_ADDR;
// Add vertices
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices,
qbuffer->size, true);
addr += qbuffer->size;
// Add sts
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->sts, qbuffer->size,
true);
addr += qbuffer->size;
// Add normal
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->normals,
qbuffer->size, true);
// Add colors
if (qbuffer->bag->color->single == nullptr) {
addr += qbuffer->size;
packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors,
qbuffer->size, true);
}
}
} // namespace Tyra
@@ -0,0 +1,87 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/std/core/path1/stdpip_clipper.hpp"
namespace Tyra {
StdpipClipper::StdpipClipper() {}
StdpipClipper::~StdpipClipper() {}
void StdpipClipper::setMVP(M4x4* t_mvp) { mvp = t_mvp; }
void StdpipClipper::init(const RendererSettings& settings) {
algorithm.init(settings);
}
void StdpipClipper::setMaxVertCount(const u32& count) { maxVertCount = count; }
void StdpipClipper::clip(StdpipQBuffer* buffer) {
TYRA_ASSERT(buffer->size <= maxVertCount / 3, "Buffer should have max ",
maxVertCount / 3, " verts if we want to clip it.");
Path1EEClipAlgorithmSettings algoSettings = {
buffer->bag->lighting != nullptr, buffer->bag->texture != nullptr,
buffer->bag->color->many != nullptr};
std::vector<Path1ClipVertex> clippedVertices;
for (u32 i = 0; i < buffer->size / 3; i++) {
std::vector<Path1ClipVertex> inputTriangle;
for (u8 j = 0; j < 3; j++) {
Path1ClipVertex vert = {
*mvp * buffer->vertices[i * 3 + j],
buffer->bag->lighting ? buffer->normals[i * 3 + j] : Vec4(),
buffer->bag->texture ? buffer->sts[i * 3 + j] : Vec4(),
buffer->bag->color->many ? buffer->colors[i * 3 + j] : Vec4()};
inputTriangle.push_back(vert);
}
std::vector<Path1ClipVertex> clippedTriangle;
algorithm.clip(&clippedTriangle, inputTriangle, algoSettings);
if (clippedTriangle.size() == 0) continue;
auto va = clippedTriangle.at(0);
for (u32 j = 1; j <= clippedTriangle.size() - 2; j++) {
auto vb = clippedTriangle.at(j);
auto vc = clippedTriangle.at((j + 1) % clippedTriangle.size());
clippedVertices.push_back(va);
clippedVertices.push_back(vb);
clippedVertices.push_back(vc);
}
}
perspectiveDivide(&clippedVertices);
moveDataToBuffer(clippedVertices, buffer);
}
void StdpipClipper::perspectiveDivide(std::vector<Path1ClipVertex>* vertices) {
for (u32 i = 0; i < vertices->size(); i++) {
(*vertices)[i].position /= (*vertices)[i].position.w;
}
}
void StdpipClipper::moveDataToBuffer(
const std::vector<Path1ClipVertex>& vertices, StdpipQBuffer* buffer) {
buffer->reallocateManually(vertices.size());
for (u32 i = 0; i < vertices.size(); i++) {
auto& vertex = vertices.at(i);
buffer->vertices[i] = vertex.position;
if (buffer->bag->texture) buffer->sts[i] = vertex.st;
if (buffer->bag->color->many) buffer->colors[i] = vertex.color;
if (buffer->bag->lighting) buffer->normals[i] = vertex.normal;
}
}
} // namespace Tyra
@@ -0,0 +1,48 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/std/core/path1/stdpip_programs_repository.hpp"
namespace Tyra {
StdpipProgramsRepository::StdpipProgramsRepository() {}
StdpipProgramsRepository::~StdpipProgramsRepository() {}
StdpipVU1Program* StdpipProgramsRepository::getProgram(
const StdpipProgramName& name) {
switch (name) {
case StdpipProgramName::StdpipAsIsColor:
return &asIsColor;
case StdpipProgramName::StdpipCullColor:
return &cullColor;
case StdpipProgramName::StdpipAsIsDirLights:
return &asIsLightingColor;
case StdpipProgramName::StdpipCullDirLights:
return &cullLightingColor;
case StdpipProgramName::StdpipAsIsTextureDirLights:
return &asIsLightingTextureColor;
case StdpipProgramName::StdpipCullTextureDirLights:
return &cullLightingTextureColor;
case StdpipProgramName::StdpipAsIsTextureColor:
return &asIsTextureColor;
case StdpipProgramName::StdpipCullTextureColor:
return &cullTextureColor;
default:
TYRA_TRAP("Unknown VU1 program name");
return &cullLightingTextureColor;
}
}
} // namespace Tyra
@@ -0,0 +1,265 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/std/core/path1/stdpip_qbuffer.hpp"
namespace Tyra {
StdpipQBuffer::StdpipQBuffer() {
size = 0;
_isDynamicallyAllocated = false;
_stAllocated = false;
_colorAllocated = false;
_normalAllocated = false;
vertices = nullptr;
colors = nullptr;
sts = nullptr;
normals = nullptr;
}
StdpipQBuffer::~StdpipQBuffer() { deallocateDynamicData(); }
void StdpipQBuffer::setMaxVertCount(const u32& count) { maxVertCount = count; }
void StdpipQBuffer::fillByPointer(const StdpipBagPackage& pkg) {
TYRA_ASSERT(pkg.size <= maxVertCount, "VU1 buffer supports only ",
maxVertCount, " verts. Provided: ", pkg.size);
deallocateDynamicData();
vertices = pkg.vertices;
sts = pkg.sts;
colors = pkg.colors;
normals = pkg.normals;
size = pkg.size;
bag = pkg.bag;
}
void StdpipQBuffer::fillByCopyMax(const StdpipBagPackage& pkg1,
const StdpipBagPackage& pkg2,
const StdpipBagPackage& pkg3) {
TYRA_ASSERT(pkg1.size <= maxVertCount / 3,
"Wrong package size (1). Provided: ", pkg1.size);
TYRA_ASSERT(pkg2.size <= maxVertCount / 3,
"Wrong package size (2). Provided: ", pkg2.size);
TYRA_ASSERT(pkg3.size <= maxVertCount / 3,
"Wrong package size (3). Provided: ", pkg3.size);
deallocateDynamicData();
size = pkg1.size + pkg2.size + pkg3.size;
allocateDynamicData(size, pkg1.bag);
for (u16 i = 0; i < pkg1.size; i++) {
vertices[i].set(pkg1.vertices[i]);
if (pkg1.bag->texture) sts[i].set(pkg1.sts[i]);
if (pkg1.bag->color->many)
colors[i].set(reinterpret_cast<const Vec4&>(pkg1.colors[i]));
if (pkg1.bag->lighting) normals[i].set(pkg1.normals[i]);
}
for (u16 i = 0; i < pkg2.size; i++) {
vertices[i + pkg1.size].set(pkg2.vertices[i]);
if (pkg1.bag->texture) sts[i + pkg1.size].set(pkg2.sts[i]);
if (pkg1.bag->color->many)
colors[i + pkg1.size].set(reinterpret_cast<const Vec4&>(pkg2.colors[i]));
if (pkg1.bag->lighting) normals[i + pkg1.size].set(pkg2.normals[i]);
}
for (u16 i = 0; i < pkg3.size; i++) {
vertices[i + pkg1.size + pkg2.size].set(pkg3.vertices[i]);
if (pkg1.bag->texture) sts[i + pkg1.size + pkg2.size].set(pkg3.sts[i]);
if (pkg1.bag->color->many)
colors[i + pkg1.size + pkg2.size].set(
reinterpret_cast<const Vec4&>(pkg3.colors[i]));
if (pkg1.bag->lighting)
normals[i + pkg1.size + pkg2.size].set(pkg3.normals[i]);
}
bag = pkg1.bag;
}
void StdpipQBuffer::fillByCopy1By2(const StdpipBagPackage& pkg1,
const StdpipBagPackage& pkg2) {
TYRA_ASSERT(pkg1.size <= maxVertCount / 3,
"Wrong package size (1). Provided: ", pkg1.size);
TYRA_ASSERT(pkg2.size <= maxVertCount / 3,
"Wrong package size (2). Provided: ", pkg2.size);
deallocateDynamicData();
size = pkg1.size + pkg2.size;
allocateDynamicData(size, pkg1.bag);
for (u16 i = 0; i < pkg1.size; i++) {
vertices[i].set(pkg1.vertices[i]);
if (pkg1.bag->texture) sts[i].set(pkg1.sts[i]);
if (pkg1.bag->color->many)
colors[i].set(reinterpret_cast<const Vec4&>(pkg1.colors[i]));
if (pkg1.bag->lighting) normals[i].set(pkg1.normals[i]);
}
for (u16 i = 0; i < pkg2.size; i++) {
vertices[i + pkg1.size].set(pkg2.vertices[i]);
if (pkg1.bag->texture) sts[i + pkg1.size].set(pkg2.sts[i]);
if (pkg1.bag->color->many)
colors[i + pkg1.size].set(reinterpret_cast<const Vec4&>(pkg2.colors[i]));
if (pkg1.bag->lighting) normals[i + pkg1.size].set(pkg2.normals[i]);
}
bag = pkg1.bag;
}
void StdpipQBuffer::fillByCopy1By3(const StdpipBagPackage& pkg) {
TYRA_ASSERT(pkg.size <= maxVertCount / 3,
"Wrong package size (1). Provided: ", pkg.size);
deallocateDynamicData();
size = pkg.size;
allocateDynamicData(size, pkg.bag);
for (u16 i = 0; i < pkg.size; i++) {
vertices[i].set(pkg.vertices[i]);
if (pkg.bag->texture) sts[i].set(pkg.sts[i]);
if (pkg.bag->color->many)
colors[i].set(reinterpret_cast<const Vec4&>(pkg.colors[i]));
if (pkg.bag->lighting) normals[i].set(pkg.normals[i]);
}
bag = pkg.bag;
}
void StdpipQBuffer::reallocateManually(const u16& t_size) {
deallocateDynamicData();
allocateDynamicData(t_size, bag);
size = t_size;
}
void StdpipQBuffer::deallocateDynamicData() {
if (_isDynamicallyAllocated) {
delete[] vertices;
if (_stAllocated) {
delete[] sts;
_stAllocated = false;
}
if (_colorAllocated) {
delete[] colors;
_colorAllocated = false;
}
if (_normalAllocated) {
delete[] normals;
_normalAllocated = false;
}
_isDynamicallyAllocated = false;
}
}
/** When we not receive maxVertCount vertices, we must align it by ourself.
* Too bad - not efficient. */
void StdpipQBuffer::allocateDynamicData(u16 size, StdpipBag* bag) {
TYRA_ASSERT(size <= maxVertCount, "Wrong size. Max buffer size in VU1 is ",
maxVertCount, ". Provided: ", size);
TYRA_ASSERT(!_isDynamicallyAllocated, "Buffer is already allocated");
vertices = new (std::align_val_t(sizeof(VECTOR))) Vec4[size];
if (bag->texture != nullptr) {
sts = new (std::align_val_t(sizeof(VECTOR))) Vec4[size];
_stAllocated = true;
}
if (bag->color->many != nullptr) {
colors = new (std::align_val_t(sizeof(VECTOR))) Vec4[size];
_colorAllocated = true;
}
if (bag->lighting != nullptr) {
normals = new (std::align_val_t(sizeof(VECTOR))) Vec4[size];
_normalAllocated = true;
}
_isDynamicallyAllocated = true;
}
bool StdpipQBuffer::any() const { return size > 0; }
void StdpipQBuffer::print() const {
auto text = getPrint(nullptr);
printf("%s\n", text.c_str());
}
void StdpipQBuffer::print(const char* name) const {
auto text = getPrint(name);
printf("%s\n", text.c_str());
}
std::string StdpipQBuffer::getPrint(const char* name) const {
std::stringstream res;
if (name) {
res << name << "(";
} else {
res << "Path1Buffer(";
}
res << std::fixed << std::setprecision(2);
res << std::endl;
res << "Size: " << static_cast<int>(size) << std::endl;
res << "Vectors: " << std::endl;
for (u32 i = 0; i < size; i++)
res << i << ": " << vertices[i].getPrint() << std::endl;
if (bag->texture != nullptr) {
res << "STs: " << std::endl;
for (u32 i = 0; i < size; i++)
res << i << ": " << sts[i].getPrint() << std::endl;
}
if (bag->color->many != nullptr) {
res << "Colors: " << std::endl;
for (u32 i = 0; i < size; i++)
res << i << ": " << colors[i].getPrint() << std::endl;
}
if (bag->lighting != nullptr) {
res << "Normals: " << std::endl;
for (u32 i = 0; i < size; i++) {
res << i << ": " << normals[i].getPrint();
if (i < size - 1) {
res << std::endl;
}
}
}
res << ")";
return res.str();
}
} // namespace Tyra
@@ -0,0 +1,320 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/std/core/path1/stdpip_qbuffer_renderer.hpp"
#include "renderer/3d/pipeline/std/core/path1/programs/stdpip_vu1_shared_defines.h"
namespace Tyra {
/**
* VU1 = 1000 vert
*
* Quadbuffering:
* 2 main buffers = 1000 / 2 = 500 vert
* 2 kick buffers = 500 / 2 = 250 vert
*
* Vert data:
* Pos + Normal + ST + Color = 4
* = 4 * 48 = 192
*
* Other data:
* mvp matrix, light matrix, tags = 14
* 20 light vectors, light intesities = 25
* = 14 + 25 = 39
*
* All data:
* = 192 + 39 = 231
*
*/
StdpipQBufferRenderer::StdpipQBufferRenderer() {
context = 0;
lastProgramName = StdipUndefinedProgram;
staticDataPacket = packet2_create(3, P2_TYPE_NORMAL, P2_MODE_CHAIN, true);
objectDataPacket = packet2_create(16, P2_TYPE_NORMAL, P2_MODE_CHAIN, true);
programsPacket = nullptr;
}
StdpipQBufferRenderer::~StdpipQBufferRenderer() {
packet2_free(packets[0]);
packet2_free(packets[1]);
packet2_free(staticDataPacket);
packet2_free(objectDataPacket);
if (programsPacket) packet2_free(programsPacket);
}
void StdpipQBufferRenderer::init(RendererCore* t_core) {
path1 = t_core->getPath1();
clipper.init(t_core->getSettings());
rendererCore = t_core;
dma_channel_initialize(DMA_CHANNEL_VIF1, NULL, 0);
dma_channel_fast_waits(DMA_CHANNEL_VIF1);
const u32 VU1_PACKET_SIZE = 16;
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);
setProgramsCache();
reinitVU1();
TYRA_LOG("Renderer3DQBufferRenderer initialized");
}
void StdpipQBufferRenderer::reinitVU1() {
sendStaticData();
uploadPrograms();
setDoubleBuffer();
}
StdpipQBuffer* StdpipQBufferRenderer::getBuffer() { return &buffers[context]; }
void StdpipQBufferRenderer::sendObjectData(
StdpipBag* bag, M4x4* mvp, RendererCoreTextureBuffers* texBuffers) const {
packet2_reset(objectDataPacket, false);
packet2_utils_vu_add_unpack_data(objectDataPacket, VU1_MVP_MATRIX_ADDR,
mvp->data, 4, false);
if (bag->lighting) {
packet2_utils_vu_add_unpack_data(objectDataPacket, VU1_LIGHTS_MATRIX_ADDR,
bag->lighting->lightMatrix, 3, false);
packet2_utils_vu_add_unpack_data(objectDataPacket, VU1_LIGHTS_DIRS_ADDR,
bag->lighting->getLightDirections(), 3,
false);
packet2_utils_vu_add_unpack_data(objectDataPacket, VU1_LIGHTS_COLORS_ADDR,
bag->lighting->getLightColors(), 4, false);
}
u8 singleColorEnabled = bag->color->single != nullptr;
if (singleColorEnabled) // Color is placed in 4th slot of
// VU1_LIGHTS_MATRIX_ADDR
packet2_utils_vu_add_unpack_data(objectDataPacket, VU1_SINGLE_COLOR_ADDR,
bag->color->single->rgba, 1, false);
packet2_utils_vu_open_unpack(objectDataPacket, VU1_OPTIONS_ADDR, false);
{
packet2_add_u32(objectDataPacket,
singleColorEnabled); // Single color enabled.
packet2_add_u32(objectDataPacket, 0); // not used, padding
packet2_add_u32(objectDataPacket, 0); // not used, padding
packet2_add_u32(objectDataPacket, 0); // not used, padding
packet2_utils_gs_add_lod(objectDataPacket, &rendererCore->gs.lod);
if (texBuffers != nullptr) {
packet2_utils_gs_add_texbuff_clut(objectDataPacket, texBuffers->core,
&rendererCore->texture.clut);
rendererCore->texture.updateClutBuffer(texBuffers->clut);
}
}
packet2_utils_vu_close_unpack(objectDataPacket);
packet2_utils_vu_add_end_tag(objectDataPacket);
dma_channel_wait(DMA_CHANNEL_VIF1, 0);
dma_channel_send_packet2(objectDataPacket, DMA_CHANNEL_VIF1, true);
}
void StdpipQBufferRenderer::setInfo(StdpipInfoBag* bag) {
rendererCore->gs.prim.antialiasing = bag->antiAliasingEnabled;
rendererCore->gs.prim.blending = bag->blendingEnabled;
rendererCore->gs.prim.shading = bag->shadingType;
}
void StdpipQBufferRenderer::sendStaticData() const {
packet2_reset(staticDataPacket, false);
packet2_utils_vu_open_unpack(staticDataPacket, VU1_SET_GIFTAG_ADDR, false);
{ packet2_utils_gif_add_set(staticDataPacket, 1); }
packet2_utils_vu_close_unpack(staticDataPacket);
packet2_utils_vu_add_end_tag(staticDataPacket);
dma_channel_wait(DMA_CHANNEL_VIF1, 0);
dma_channel_send_packet2(staticDataPacket, DMA_CHANNEL_VIF1, true);
}
void StdpipQBufferRenderer::setProgramsCache() {
VU1Program** programs = new VU1Program*[8];
programs[0] = repository.getProgram(StdpipCullColor);
programs[1] = repository.getProgram(StdpipAsIsColor);
programs[2] = repository.getProgram(StdpipCullDirLights);
programs[3] = repository.getProgram(StdpipAsIsDirLights);
programs[4] = repository.getProgram(StdpipCullTextureDirLights);
programs[5] = repository.getProgram(StdpipAsIsTextureDirLights);
programs[6] = repository.getProgram(StdpipCullTextureColor);
programs[7] = repository.getProgram(StdpipAsIsTextureColor);
programsPacket = path1->createProgramsCache(programs, 8, 0);
delete[] programs;
}
void StdpipQBufferRenderer::uploadPrograms() {
dma_channel_wait(DMA_CHANNEL_VIF1, 0);
dma_channel_send_packet2(programsPacket, DMA_CHANNEL_VIF1, true);
dma_channel_wait(DMA_CHANNEL_VIF1, 0);
}
void StdpipQBufferRenderer::setDoubleBuffer() {
u16 startingAddr = VU1_LAST_ITEM_ADDR + 1;
const u16 bufferMaxSize = 1000;
bufferSize = (bufferMaxSize - startingAddr) / 2;
path1->setDoubleBuffer(startingAddr, bufferSize);
bufferSize -= 1; // Because we don't want to upload anything from first
// buffer, to first addr of second buffer
}
void StdpipQBufferRenderer::cull(StdpipQBuffer* buffer) {
if (buffer->size == 0) {
return;
}
auto program = getCullProgramByBag(buffer->bag);
addBufferDataToPacket(program, buffer);
sendPacket();
}
// void StdpipQBufferRenderer::sendFinishTag() {
// StdpipQBufferRenderer way proposition
// auto program = path1->getProgramByName(Draw_Finish);
// addBufferDataToPacket(program, nullptr);
// sendPacket();
// packet2_t* packet2 = packet2_create(8, P2_TYPE_NORMAL, P2_MODE_CHAIN,
// true); auto program =
// static_cast<VU1DrawFinish*>(getProgramByName(Draw_Finish));
// program->addTag(packet2, prim);
// packet2_utils_vu_add_start_program(packet2,
// program->getDestinationAddress()); packet2_utils_vu_add_end_tag(packet2);
// dma_channel_wait(DMA_CHANNEL_VIF1, 0);
// dma_channel_send_packet2(packet2, DMA_CHANNEL_VIF1, true);
// packet2_free(packet2);
// }
void StdpipQBufferRenderer::clip(StdpipQBuffer* buffer) {
if (buffer->size == 0) {
return;
}
auto program = getAsIsProgramByBag(buffer->bag);
clipper.clip(buffer);
if (buffer->any()) {
if (buffer) addBufferDataToPacket(program, buffer);
sendPacket();
}
}
void StdpipQBufferRenderer::clearLastProgramName() {
lastProgramName = StdipUndefinedProgram;
}
void StdpipQBufferRenderer::addBufferDataToPacket(StdpipVU1Program* program,
StdpipQBuffer* buffer) {
currentPacket = packets[context];
packet2_reset(currentPacket, false);
program->addBufferDataToPacket(currentPacket, buffer, &rendererCore->gs.prim);
if (lastProgramName != program->getName()) {
packet2_utils_vu_add_start_program(currentPacket,
program->getDestinationAddress());
lastProgramName = program->getName();
} else {
packet2_utils_vu_add_continue_program(currentPacket);
}
packet2_utils_vu_add_end_tag(currentPacket);
}
void StdpipQBufferRenderer::sendPacket() {
dma_channel_wait(DMA_CHANNEL_VIF1, 0);
dma_channel_send_packet2(currentPacket, DMA_CHANNEL_VIF1, true);
// Switch packet, so we can proceed during DMA transfer
context = !context;
}
void StdpipQBufferRenderer::setMaxVertCount(const u32& count) {
buffers[0].setMaxVertCount(count);
buffers[1].setMaxVertCount(count);
clipper.setMaxVertCount(count);
}
StdpipVU1Program* StdpipQBufferRenderer::getAsIsProgramByBag(
const StdpipBag* bag) {
auto programType = getDrawProgramTypeByBag(bag);
if (programType == StdpipVU1TextureDirLights)
return getProgramByName(StdpipAsIsTextureDirLights);
else if (programType == StdpipVU1DirLights)
return getProgramByName(StdpipAsIsDirLights);
else if (programType == StdpipVU1TextureColor)
return getProgramByName(StdpipAsIsTextureColor);
else
return getProgramByName(StdpipAsIsColor);
}
StdpipVU1Program* StdpipQBufferRenderer::getCullProgramByBag(
const StdpipBag* bag) {
auto programType = getDrawProgramTypeByBag(bag);
return getCullProgramByType(programType);
}
StdpipVU1Program* StdpipQBufferRenderer::getProgramByName(
const StdpipProgramName& name) {
return repository.getProgram(name);
}
StdpipVU1Program* StdpipQBufferRenderer::getCullProgramByParams(
const bool& isLightingEnabled, const bool& isTextureEnabled) {
auto type = getDrawProgramTypeByParams(isLightingEnabled, isTextureEnabled);
return getCullProgramByType(type);
}
StdpipVU1Program* StdpipQBufferRenderer::getCullProgramByType(
const StdpipProgramType& programType) {
if (programType == StdpipVU1TextureDirLights)
return getProgramByName(StdpipCullTextureDirLights);
else if (programType == StdpipVU1DirLights)
return getProgramByName(StdpipCullDirLights);
else if (programType == StdpipVU1TextureColor)
return getProgramByName(StdpipCullTextureColor);
else
return getProgramByName(StdpipCullColor);
}
StdpipProgramType StdpipQBufferRenderer::getDrawProgramTypeByBag(
const StdpipBag* bag) const {
auto isLightingEnabled = bag->lighting != nullptr;
auto isTextureEnabled = bag->texture != nullptr;
return getDrawProgramTypeByParams(isLightingEnabled, isTextureEnabled);
}
StdpipProgramType StdpipQBufferRenderer::getDrawProgramTypeByParams(
const bool& isLightingEnabled, const bool& isTextureEnabled) const {
if (isLightingEnabled && isTextureEnabled)
return StdpipVU1TextureDirLights;
else if (isLightingEnabled)
return StdpipVU1DirLights;
else if (isTextureEnabled)
return StdpipVU1TextureColor;
else
return StdpipVU1Color;
}
} // namespace Tyra
@@ -0,0 +1,83 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/std/core/path1/stdpip_vu1_program.hpp"
namespace Tyra {
StdpipVU1Program::StdpipVU1Program(const StdpipProgramName& t_name,
u32* t_start, u32* t_end,
const u32& t_reglist,
const u8& t_reglistCount,
const u8& t_elementsPerVertex)
: VU1Program(t_start, t_end),
name(t_name),
reglistCount(t_reglistCount),
elementsPerVertex(t_elementsPerVertex),
reglist(t_reglist) {
packetSize = packet2_utils_get_packet_size_for_program(start, end);
programSize = calculateProgramSize();
}
StdpipVU1Program::~StdpipVU1Program() {}
const StdpipProgramName& StdpipVU1Program::getName() const { return name; }
u32& StdpipVU1Program::getReglist() { return reglist; }
void StdpipVU1Program::addBufferDataToPacket(packet2_t* packet,
StdpipQBuffer* buffer,
prim_t* prim) {
addStandardBufferDataToPacket(packet, buffer, prim);
addProgramQBufferDataToPacket(packet, buffer);
}
void StdpipVU1Program::addStandardBufferDataToPacket(packet2_t* packet,
StdpipQBuffer* buffer,
prim_t* prim) {
if (buffer->bag->texture)
prim->mapping = 1;
else
prim->mapping = 0;
packet2_utils_vu_open_unpack(packet, 0, true);
{
packet2_add_float(packet, 2048.0F); // scale
packet2_add_float(packet, 2048.0F); // scale
packet2_add_float(packet,
static_cast<float>(0xFFFFFF) / 32.0F); // scale
packet2_add_u32(packet, buffer->size); // vertex count
packet2_utils_gs_add_prim_giftag(packet, prim, buffer->size, reglist,
reglistCount, 0);
}
packet2_utils_vu_close_unpack(packet);
}
u16 StdpipVU1Program::getMaxVertCount(const bool& singleColorEnabled,
const u16& bufferSize) const {
u16 res = bufferSize - 4;
u8 colorElementsPerVertex =
singleColorEnabled ? (elementsPerVertex - 1) : elementsPerVertex;
res /= (colorElementsPerVertex + reglistCount);
// Buffer size = VU1 double buffer size (xtop)
// res = qbuffer size (directly inside VU1)
// Must be dividable by 3 and the result also dividable by 3. Why?
// 1st dividable reason - triangle, and packaging system in 3d rendering
// 2nd dividable reason - subpackaging system. We are splitting packages into
// 3 subpackages in 3d renderer.
res = res / 3 / 3;
res = res * 3 * 3;
return res;
}
} // namespace Tyra
@@ -0,0 +1,227 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/std/core/std_pipeline_core.hpp"
#include "renderer/core/renderer_core.hpp"
#include "thread/threading.hpp"
// #define TYRA_RENDERER_VERBOSE_LOG 1
#ifdef TYRA_RENDERER_VERBOSE_LOG
#define Verbose(...) Debug::writeLines("VRB: ", ##__VA_ARGS__, "\n")
#else
#define Verbose(...) ((void)0)
#endif
namespace Tyra {
StdPipelineCore::StdPipelineCore() { maxVertCount = 0; }
StdPipelineCore::~StdPipelineCore() {}
void StdPipelineCore::init(RendererCore* t_core) {
rendererCore = t_core;
qbufferRenderer.init(t_core);
packager.init(&rendererCore->renderer3D.frustumPlanes);
}
void StdPipelineCore::reinitStandardVU1Programs() {
qbufferRenderer.reinitVU1();
}
u32 StdPipelineCore::getMaxVertCountByBag(const StdpipBag* bag) {
return qbufferRenderer.getCullProgramByBag(bag)->getMaxVertCount(
bag->color->many == nullptr, qbufferRenderer.getBufferSize());
}
u32 StdPipelineCore::getMaxVertCountByParams(const bool& isSingleColor,
const bool& isLightingEnabled,
const bool& isTextureEnabled) {
return qbufferRenderer
.getCullProgramByParams(isLightingEnabled, isTextureEnabled)
->getMaxVertCount(isSingleColor, qbufferRenderer.getBufferSize());
}
void StdPipelineCore::render(StdpipBag* bag, StdpipBagPackagesBBox* bbox) {
if (bag->count <= 0) return;
TYRA_ASSERT(bag->vertices != nullptr,
"Vertices are required in 3D render bag!");
TYRA_ASSERT(bag->info != nullptr, "Info bag is required in 3D render bag!");
TYRA_ASSERT(bag->info->model != nullptr,
"Info bag's model pointer is empty!");
TYRA_ASSERT(bag->color != nullptr, "Color bag is required in 3D render bag!");
TYRA_ASSERT(bag->color->single || bag->color->many,
"At least one color is required in 3D render bag!");
TYRA_ASSERT((!bag->color->many && !bag->lighting) ||
(bag->color->many && !bag->lighting) ||
(!bag->color->many && bag->lighting),
"Multicolor is not supported with lighting, please choose one!");
TYRA_ASSERT(
!bag->lighting || (bag->lighting->lightMatrix && bag->lighting->normals),
"If you want lighting, please provide light matrix and normals!");
TYRA_ASSERT(
!bag->texture || (bag->texture->texture && bag->texture->coordinates),
"If you want texture, please provide texture and coordinates!");
StdpipBagPackagesBBox* renderBbox;
u32 maxVertCount = getMaxVertCountByBag(bag);
setMaxVertCount(maxVertCount);
if (!bbox)
renderBbox =
new StdpipBagPackagesBBox(bag->vertices, bag->count, maxVertCount);
else
renderBbox = bbox;
auto frustumCheck = renderBbox->getMainBBox()->clipIsInFrustum(
rendererCore->renderer3D.frustumPlanes.getAll(), *bag->info->model);
auto mvp = rendererCore->renderer3D.getViewProj() * *bag->info->model;
if (frustumCheck == OUTSIDE_FRUSTUM) return;
RendererCoreTextureBuffers* texBuffers = nullptr;
if (bag->texture) {
auto temp = rendererCore->texture.useTexture(bag->texture->texture);
texBuffers = new RendererCoreTextureBuffers{temp.id, temp.core, temp.clut};
}
qbufferRenderer.clearLastProgramName();
qbufferRenderer.sendObjectData(bag, &mvp, texBuffers);
packager.setRenderBBox(renderBbox);
qbufferRenderer.setClipperMVP(&mvp);
qbufferRenderer.setInfo(bag->info);
if (frustumCheck == IN_FRUSTUM ||
(frustumCheck == PARTIALLY_IN_FRUSTUM && bag->info->noClipChecks)) {
u16 packagesCount = 0;
auto biggerPkgs = packager.create(&packagesCount, bag, maxVertCount);
Verbose("Material - in frustum. Pkgs: ", packagesCount,
" size: ", static_cast<int>(biggerPkgs[0].size));
for (u16 i = 0; i < packagesCount; i++) {
Verbose(i, " package - cull by data pointer");
auto buffer = qbufferRenderer.getBuffer();
buffer->fillByPointer(biggerPkgs[i]);
qbufferRenderer.cull(buffer);
}
delete[] biggerPkgs;
} else if (frustumCheck == PARTIALLY_IN_FRUSTUM) {
u16 packagesCount = 0;
if (bag->count >= maxVertCount * 2) {
auto packages = packager.create(&packagesCount, bag, maxVertCount);
Verbose("Material - partial. Packages: ", packagesCount);
renderPkgs(packages, packagesCount);
delete[] packages;
} else {
auto subpkgs = packager.create(&packagesCount, bag, maxVertCount / 3);
Verbose("Material - partial. Subpackages: ", packagesCount);
renderSubpkgs(subpkgs, packagesCount);
delete[] subpkgs;
}
}
if (!bbox) delete renderBbox;
if (texBuffers) delete texBuffers;
Threading::switchThread();
Verbose("Render finished");
}
void StdPipelineCore::renderPkgs(StdpipBagPackage* packages, u16 count) {
for (u16 i = 0; i < count; i++) {
if (packages[i].isInFrustum == IN_FRUSTUM) {
Verbose(i, " - package in frustum -> cull");
auto buffer = qbufferRenderer.getBuffer();
buffer->fillByPointer(packages[i]);
qbufferRenderer.cull(buffer);
} else if (packages[i].isInFrustum == PARTIALLY_IN_FRUSTUM) {
u16 subpkgsSize = 0;
auto packages1By3 =
packager.create(&subpkgsSize, packages[i], maxVertCount / 3);
Verbose(i, " - partial package. Created subpkgs: ", subpkgsSize);
renderSubpkgs(packages1By3, subpkgsSize);
delete[] packages1By3;
}
Verbose(i, " - package skipped (outside)");
}
}
void StdPipelineCore::renderSubpkgs(StdpipBagPackage* subpkgs, u16 count) {
std::vector<u16> doneIndexes;
std::vector<u16> loadedIndexes;
// Check if some subpkgs are full in frustum
for (u16 i = 0; i < count; i++) {
if (subpkgs[i].isInFrustum == IN_FRUSTUM) {
if (loadedIndexes.size() <= 1) {
Verbose(i, " - subpackage in frustum -> load");
loadedIndexes.push_back(i);
} else { // Hmm, this will never happen?
Verbose(i, " - subpackage in frustum, cull all 3 subpkgs");
auto buffer = qbufferRenderer.getBuffer();
buffer->fillByCopyMax(subpkgs[loadedIndexes[0]],
subpkgs[loadedIndexes[1]], subpkgs[i]);
qbufferRenderer.cull(buffer);
doneIndexes.push_back(loadedIndexes[0]);
doneIndexes.push_back(loadedIndexes[1]);
doneIndexes.push_back(i);
loadedIndexes.clear();
}
}
}
if (loadedIndexes.size() == 2) {
Verbose("2 in frustum subpkgs left -> cull them");
auto buffer = qbufferRenderer.getBuffer();
buffer->fillByCopy1By2(subpkgs[loadedIndexes[0]],
subpkgs[loadedIndexes[1]]);
qbufferRenderer.cull(buffer);
doneIndexes.push_back(loadedIndexes[0]);
doneIndexes.push_back(loadedIndexes[1]);
} else if (loadedIndexes.size() == 1) {
Verbose("1 in frustum subpkg left -> cull it");
auto buffer = qbufferRenderer.getBuffer();
buffer->fillByPointer(subpkgs[loadedIndexes[0]]);
qbufferRenderer.cull(buffer);
doneIndexes.push_back(loadedIndexes[0]);
}
for (u16 i = 0; i < count; i++) {
bool isSkip = subpkgs[i].isInFrustum == OUTSIDE_FRUSTUM ||
std::find(doneIndexes.begin(), doneIndexes.end(), i) !=
doneIndexes.end();
if (isSkip) {
Verbose(i, " - subpkg skipped, already rendered/outside");
continue;
}
auto buffer = qbufferRenderer.getBuffer();
buffer->fillByCopy1By3(subpkgs[i]);
Verbose(i, " - subpkg out/partial -> send to clipper");
qbufferRenderer.clip(buffer);
}
}
void StdPipelineCore::setMaxVertCount(const u32& count) {
maxVertCount = count;
packager.setMaxVertCount(count);
qbufferRenderer.setMaxVertCount(count);
}
} // namespace Tyra
@@ -0,0 +1,221 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/std/std_pipeline.hpp"
namespace Tyra {
StdPipeline::StdPipeline() { colorsCache = new Vec4[4]; }
StdPipeline::~StdPipeline() { delete[] colorsCache; }
void StdPipeline::init(RendererCore* t_core) {
rendererCore = t_core;
core.init(t_core);
}
void StdPipeline::onUse() { core.reinitStandardVU1Programs(); }
void StdPipeline::render(Mesh* mesh, const StdpipOptions* options) {
auto model = mesh->getModelMatrix();
MeshFrame* frameFrom = mesh->getFramesCount() > 0
? mesh->getFrame(mesh->getCurrentAnimationFrame())
: mesh->getFrame(0);
MeshFrame* frameTo = mesh->getFramesCount() > 0
? mesh->getFrame(mesh->getNextAnimationFrame())
: nullptr;
auto* infoBag = getInfoBag(mesh, options, &model);
if (options->lighting) setLightingColorsCache(options->lighting);
for (u32 i = 0; i < mesh->getMaterialsCount(); i++) {
auto* material = mesh->getMaterial(i);
// 2x bufory[maxVertCount*2] -> pętla po mniejszych częściach i czestsze
// rendery
// TODO: Double buffering in future
// auto maxVertCount = core->renderer3D.getMaxVertCountByParams(
// material->isSingleColorActivated(), material->getNormalFaces(),
// material->getTextureCoordFaces());
StdpipBag bag;
addVertices(mesh, material, &bag, frameFrom, frameTo);
bag.info = infoBag;
bag.color = getColorBag(mesh, material, frameFrom, frameTo);
bag.texture = getTextureBag(mesh, material, frameFrom, frameTo);
bag.lighting =
getLightingBag(mesh, material, &model, frameFrom, frameTo, options);
core.render(&bag);
deallocDrawBags(&bag, material);
}
delete infoBag;
}
void StdPipeline::addVertices(Mesh* mesh, MeshMaterial* material,
StdpipBag* bag, MeshFrame* frameFrom,
MeshFrame* frameTo) const {
bag->count = material->getFacesCount();
bag->vertices = new Vec4[bag->count];
for (u32 i = 0; i < bag->count; i++) {
auto& face = material->getVertexFaces()[i];
if (frameTo == nullptr) {
bag->vertices[i] = frameFrom->getVertices()[face];
} else {
Vec4::setLerp(&bag->vertices[i], frameFrom->getVertices()[face],
frameTo->getVertices()[face],
mesh->getAnimState().interpolation);
}
}
}
StdpipInfoBag* StdPipeline::getInfoBag(Mesh* mesh, const StdpipOptions* options,
M4x4* model) const {
auto* result = new StdpipInfoBag();
if (options) {
result->antiAliasingEnabled = options->antiAliasingEnabled;
result->blendingEnabled = options->blendingEnabled;
result->shadingType = options->shadingType;
result->noClipChecks = options->noClipChecks;
} else {
result->antiAliasingEnabled = false;
result->blendingEnabled = true;
result->shadingType = StdpipShadingFlat;
result->noClipChecks = true;
}
result->model = model;
return result;
}
StdpipColorBag* StdPipeline::getColorBag(Mesh* mesh, MeshMaterial* material,
MeshFrame* frameFrom,
MeshFrame* frameTo) const {
auto* result = new StdpipColorBag();
if (material->isSingleColorActivated()) {
result->single = &material->singleColor;
} else {
result->many = new Color[material->getFacesCount()];
for (u32 i = 0; i < material->getFacesCount(); i++) {
auto& face = material->getColorFaces()[i];
if (frameTo == nullptr) {
result->many[i] = frameFrom->getColors()[face];
} else {
Vec4::setLerp(
reinterpret_cast<Vec4*>(&result->many[i]),
reinterpret_cast<const Vec4&>(frameFrom->getColors()[face]),
reinterpret_cast<const Vec4&>(frameTo->getColors()[face]),
mesh->getAnimState().interpolation);
}
}
}
return result;
}
StdpipTextureBag* StdPipeline::getTextureBag(Mesh* mesh, MeshMaterial* material,
MeshFrame* frameFrom,
MeshFrame* frameTo) {
if (!material->getTextureCoordFaces()) return nullptr;
auto* result = new StdpipTextureBag();
result->texture =
rendererCore->texture.repository.getBySpriteOrMesh(material->getId());
TYRA_ASSERT(result->texture, "Texture for material id: ", material->getId(),
" was not found in texture repository!");
result->coordinates = new Vec4[material->getFacesCount()];
for (u32 i = 0; i < material->getFacesCount(); i++) {
auto& face = material->getTextureCoordFaces()[i];
if (frameTo == nullptr) {
result->coordinates[i] = frameFrom->getTextureCoords()[face];
} else {
Vec4::setLerp(&result->coordinates[i],
frameFrom->getTextureCoords()[face],
frameTo->getTextureCoords()[face],
mesh->getAnimState().interpolation);
}
}
return result;
}
StdpipLightingBag* StdPipeline::getLightingBag(
Mesh* mesh, MeshMaterial* material, M4x4* model, MeshFrame* frameFrom,
MeshFrame* frameTo, const StdpipOptions* options) const {
if (!material->getNormalFaces() || options == nullptr ||
options->lighting == nullptr)
return nullptr;
auto* result = new StdpipLightingBag(true);
result->lightMatrix = model;
result->setLightsManually(colorsCache,
options->lighting->directionalDirections);
result->normals = new Vec4[material->getFacesCount()];
for (u32 i = 0; i < material->getFacesCount(); i++) {
auto& face = material->getNormalFaces()[i];
if (frameTo == nullptr) {
result->normals[i] = frameFrom->getNormals()[face];
} else {
Vec4::setLerp(&result->normals[i], frameFrom->getNormals()[face],
frameTo->getNormals()[face],
mesh->getAnimState().interpolation);
}
}
return result;
}
void StdPipeline::setLightingColorsCache(
StdpipLightingOptions* lightingOptions) {
for (int i = 0; i < 3; i++) {
colorsCache[i] =
reinterpret_cast<Vec4&>(lightingOptions->directionalColors[i]);
}
colorsCache[3] = reinterpret_cast<Vec4&>(*lightingOptions->ambientColor);
}
void StdPipeline::deallocDrawBags(StdpipBag* bag,
MeshMaterial* material) const {
if (bag->color->many) {
delete[] bag->color->many;
}
if (bag->texture) {
delete[] bag->texture->coordinates;
delete bag->texture;
}
if (bag->lighting) {
delete[] bag->lighting->normals;
delete bag->lighting;
}
delete[] bag->vertices;
delete bag->color;
}
} // namespace Tyra
+27
View File
@@ -0,0 +1,27 @@
/*
# ______ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2020, tyra - https://github.com/h4570/tyra
# Licenced under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/renderer_3d.hpp"
namespace Tyra {
Renderer3D::Renderer3D() { currentPipeline = nullptr; }
Renderer3D::~Renderer3D() {}
void Renderer3D::usePipeline(Renderer3DPipeline* pipeline) {
if (currentPipeline != pipeline) {
currentPipeline = pipeline;
currentPipeline->onUse();
}
}
} // namespace Tyra