moved from h4570/tyra
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "include/engine.hpp"
|
||||
|
||||
#include <kernel.h>
|
||||
#include <stdio.h>
|
||||
#include <sifrpc.h>
|
||||
#include <time.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "include/modules/vu1.hpp"
|
||||
#include "include/utils/debug.hpp"
|
||||
|
||||
// VU1 micro program
|
||||
extern u32 VU1Draw3D_CodeStart __attribute__((section(".vudata")));
|
||||
extern u32 VU1Draw3D_CodeEnd __attribute__((section(".vudata")));
|
||||
//
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
Engine::Engine()
|
||||
{
|
||||
SifInitRpc(0);
|
||||
srand(time(NULL));
|
||||
VU1::uploadProgram(0, &VU1Draw3D_CodeStart, &VU1Draw3D_CodeEnd);
|
||||
audio.startThread();
|
||||
isInitialized = 0;
|
||||
isScreenInitialized = 0;
|
||||
mainThreadId = GetThreadId();
|
||||
}
|
||||
|
||||
Engine::~Engine() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
void Engine::setScreen(ScreenSettings &t_settings)
|
||||
{
|
||||
screen = t_settings;
|
||||
isScreenInitialized = true;
|
||||
}
|
||||
|
||||
void Engine::setDefaultScreen()
|
||||
{
|
||||
screen.projectionScale = 4096.0F;
|
||||
screen.nearPlaneDist = 2.0F;
|
||||
screen.farPlaneDist = 2000.0F;
|
||||
screen.fov = 60.0F;
|
||||
screen.aspectRatio = 4.0F / 3.0F;
|
||||
screen.width = 640.0F;
|
||||
screen.height = 480.0F;
|
||||
isScreenInitialized = true;
|
||||
}
|
||||
|
||||
void Engine::init(Game *t_game, u32 t_gifPacketSize)
|
||||
{
|
||||
if (!isScreenInitialized)
|
||||
PRINT_ERR("Cant init because screen was not set!");
|
||||
else if (isInitialized)
|
||||
PRINT_ERR("Already initialized!");
|
||||
else
|
||||
{
|
||||
game = t_game;
|
||||
renderer = new Renderer(t_gifPacketSize, &screen);
|
||||
isInitialized = true;
|
||||
game->onInit();
|
||||
gameLoop();
|
||||
}
|
||||
}
|
||||
|
||||
/** Do not call this method. This is used in gameLoop() to maintain multithreading */
|
||||
void Engine::wakeup(s32 t_alarmId, u16 t_time, void *t_common)
|
||||
{
|
||||
(void)t_alarmId;
|
||||
(void)t_time;
|
||||
iWakeupThread(*(int *)t_common);
|
||||
ExitHandler();
|
||||
}
|
||||
|
||||
void Engine::gameLoop()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
pad.update();
|
||||
game->onUpdate();
|
||||
if (fpsDelayer++ >= 4)
|
||||
{
|
||||
fps = timer.getFPS();
|
||||
fpsDelayer = 0;
|
||||
}
|
||||
timer.primeTimer();
|
||||
renderer->endFrame(fps);
|
||||
/** -6~ FPS */
|
||||
SetAlarm(fps > 49.0F ? 24 : 48, &Engine::wakeup, &mainThreadId);
|
||||
SleepThread();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_ENGINE_
|
||||
#define _TYRA_ENGINE_
|
||||
|
||||
#include <tamtypes.h>
|
||||
#include "game.hpp"
|
||||
#include "models/screen_settings.hpp"
|
||||
#include "models/math/matrix.hpp"
|
||||
#include "modules/renderer.hpp"
|
||||
#include "modules/timer.hpp"
|
||||
#include "modules/pad.hpp"
|
||||
#include "modules/audio.hpp"
|
||||
|
||||
class Engine
|
||||
{
|
||||
|
||||
public:
|
||||
Engine();
|
||||
~Engine();
|
||||
|
||||
void init(Game *t_game, u32 t_gifPacketSize);
|
||||
void setDefaultScreen();
|
||||
void setScreen(ScreenSettings &t_settings);
|
||||
Renderer *renderer;
|
||||
Audio audio;
|
||||
ScreenSettings screen;
|
||||
Pad pad;
|
||||
float fps;
|
||||
|
||||
private:
|
||||
u8 fpsDelayer;
|
||||
Timer timer;
|
||||
u8 isInitialized, isScreenInitialized;
|
||||
void gameLoop();
|
||||
Game *game;
|
||||
s32 mainThreadId;
|
||||
static void wakeup(s32 t_alarmId, u16 t_time, void *t_common);
|
||||
|
||||
// ThreadManager threadManager;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_GAME_
|
||||
#define _TYRA_GAME_
|
||||
|
||||
#include <tamtypes.h>
|
||||
|
||||
class Game
|
||||
{
|
||||
|
||||
public:
|
||||
virtual ~Game(){};
|
||||
virtual void onInit() = 0;
|
||||
virtual void onUpdate() = 0;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_BMP_LOADER_
|
||||
#define _TYRA_BMP_LOADER_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <tamtypes.h>
|
||||
#include "../models/texture.hpp"
|
||||
|
||||
/** Class responsible for loading images in bmp format */
|
||||
class BmpLoader
|
||||
{
|
||||
|
||||
public:
|
||||
BmpLoader();
|
||||
~BmpLoader();
|
||||
|
||||
void load(Texture &o_texture, char *t_subfolder, char *t_name, char *t_extension);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_DFF_LOADER_
|
||||
#define _TYRA_DFF_LOADER_
|
||||
|
||||
#include "../models/dff_model.hpp"
|
||||
#include "./dff_structure.hpp"
|
||||
|
||||
/** Class responsible for loading&parsing .obj 3D files */
|
||||
class DffLoader
|
||||
{
|
||||
|
||||
public:
|
||||
DffLoader();
|
||||
~DffLoader();
|
||||
|
||||
void load(RwClump &o_clump, char *t_fileName, float t_scale);
|
||||
void serialize(RwClump &t_clump, u8 *t_data, float t_scale);
|
||||
|
||||
static u8 readByteFromArrayLE(u8 *t_buffer, u32 &t_ptrPos);
|
||||
static u16 readWordFromArrayLE(u8 *t_buffer, u32 &t_ptrPos);
|
||||
static u32 readDwordFromArrayLE(u8 *t_buffer, u32 &t_ptrPos);
|
||||
static float readFloatFromArrayLE(u8 *t_buffer, u32 &t_ptrPos);
|
||||
static u8 *readData(u8 *t_buffer, u32 &t_ptrPos, u32 t_dataSize);
|
||||
static char *readString(u8 *t_buffer, u32 &t_ptrPos, u32 t_dataSize = 0);
|
||||
|
||||
void readSectionHeader(RwSectionHeader &t_sh, u8 *t_buffer, u32 &t_ptrPos);
|
||||
|
||||
private:
|
||||
// ---
|
||||
void readFrameListData(RwFrameListData &t_frd, u8 *t_buffer, u32 &t_ptrPos);
|
||||
void readClumpData(RwClumpData &t_cd, u8 *t_buffer, u32 &t_ptrPos);
|
||||
void readGeometryListData(RwGeometryListData &t_gld, u8 *t_buffer, u32 &t_ptrPos);
|
||||
void readGeometryExtension(RwGeometryExtension &t_ge, u8 *t_buffer, u32 &t_ptrPos);
|
||||
void readGeometryData(RwGeometryData &t_gd, u8 *t_buffer, u32 &t_ptrPos, float t_scale);
|
||||
void readMaterialListData(RwMaterialListData &t_mld, u8 *t_buffer, u32 &t_ptrPos);
|
||||
void readMaterialData(RwMaterialData &t_md, u8 *t_buffer, u32 &t_ptrPos);
|
||||
void readTextureData(RwTextureData &t_td, u8 *t_buffer, u32 &t_ptrPos);
|
||||
void readStringData(RwString &t_s, u8 *bt_uffer, u32 &t_ptrPos);
|
||||
// ---
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_DFF_STRUCTURE_
|
||||
#define _TYRA_DFF_STRUCTURE_
|
||||
|
||||
#include <tamtypes.h>
|
||||
#include "../models/math/vector3.hpp"
|
||||
|
||||
enum RwGeometryDataFlags
|
||||
{
|
||||
rwOBJECT_VERTEX_TRISTRIP = 0x01,
|
||||
rwOBJECT_VERTEX_POS = 0x02,
|
||||
rwOBJECT_VERTEX_TEXTURED = 0x04,
|
||||
rwOBJECT_VERTEX_PRELIT = 0x08,
|
||||
rwOBJECT_VERTEX_NORMALS = 0x10,
|
||||
rwOBJECT_VERTEX_LIGHT = 0x20,
|
||||
rwOBJECT_VERTEX_MODULATE_MATERIAL_COLOR = 0x40,
|
||||
rwOBJECT_VERTEX_TEXTURED_2 = 0x80
|
||||
};
|
||||
|
||||
class RwSectionHeader
|
||||
{
|
||||
public:
|
||||
u32 sectionType;
|
||||
u32 sectionSize;
|
||||
u32 versionNumber;
|
||||
};
|
||||
|
||||
class RwFrameListChunk
|
||||
{
|
||||
public:
|
||||
~RwFrameListChunk() { delete[] rotationalMatrix; }
|
||||
float *rotationalMatrix; // [ROT_MAT_DIM]
|
||||
float coordinatesOffsetX;
|
||||
float coordinatesOffsetY;
|
||||
float coordinatesOffsetZ;
|
||||
u32 parentFrame; // 0xFFFFFFFF = NONE
|
||||
u32 unk1;
|
||||
};
|
||||
|
||||
// Section: Frame List
|
||||
class RwFrameListData : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
~RwFrameListData() { delete frameInformation; }
|
||||
static const u32 ROT_MAT_DIM = 9;
|
||||
u32 frameCount;
|
||||
|
||||
RwFrameListChunk *frameInformation; // [frameCount]
|
||||
};
|
||||
|
||||
class RwFrame : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
~RwFrame() { delete[] frameName; }
|
||||
u8 *frameName; // [sectionSize] - should be interpreted as string
|
||||
};
|
||||
|
||||
class RwFrameListExtension : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
RwFrame frame;
|
||||
};
|
||||
|
||||
class RwFrameList : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
RwFrameListData data;
|
||||
~RwFrameList() { delete[] extensions; }
|
||||
RwFrameListExtension *extensions;
|
||||
};
|
||||
// ---
|
||||
|
||||
class RwGeometryDataHeader
|
||||
{
|
||||
public:
|
||||
u16 flags;
|
||||
u16 unk1;
|
||||
u32 triangleCount;
|
||||
u32 vertexCount;
|
||||
u32 morphTargetCount;
|
||||
};
|
||||
|
||||
class RwGeometryDataLightingHeader
|
||||
{ // IF versionNumber = 4099 - according to not complete documentation
|
||||
public:
|
||||
float ambient;
|
||||
float diffuse;
|
||||
float specular;
|
||||
};
|
||||
|
||||
class RwGeometryDataColorInformationChunk
|
||||
{ // if rwOBJECT_VERTEX_PREILIT in flags
|
||||
public:
|
||||
u8 red;
|
||||
u8 green;
|
||||
u8 blue;
|
||||
u8 alpha;
|
||||
};
|
||||
|
||||
class RwGeometryDataTextureMappingInformationChunk
|
||||
{ // if rwOBJECT_VERTEX_TEXTURED in flags
|
||||
public:
|
||||
float u;
|
||||
float v;
|
||||
};
|
||||
|
||||
class RwGeometryDataFaceInformation
|
||||
{
|
||||
public:
|
||||
u16 vertex2; // this
|
||||
u16 vertex1; // is
|
||||
u16 flags; // weird
|
||||
u16 vertex3; // order
|
||||
};
|
||||
|
||||
// Section: Geometry
|
||||
class RwGeometryData : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
~RwGeometryData()
|
||||
{
|
||||
delete colorInformation;
|
||||
delete textureMappingInformation;
|
||||
delete faceInformation;
|
||||
delete vertexInformation;
|
||||
delete normalInformation;
|
||||
}
|
||||
RwGeometryDataHeader dataHeader;
|
||||
|
||||
RwGeometryDataLightingHeader lightingHeader;
|
||||
|
||||
RwGeometryDataColorInformationChunk *colorInformation; // [vertexCount]
|
||||
|
||||
RwGeometryDataTextureMappingInformationChunk *textureMappingInformation; // [vertexCount]
|
||||
|
||||
RwGeometryDataFaceInformation *faceInformation; // [triangleCount]
|
||||
|
||||
class RwGeometryDataNonameInfo
|
||||
{
|
||||
public:
|
||||
float boundingSphereX;
|
||||
float boundingSphereY;
|
||||
float boundingSphereZ;
|
||||
float boundingSphereR;
|
||||
u32 hasPosition;
|
||||
u32 hasNormals;
|
||||
} nonameInfo;
|
||||
|
||||
Vector3 *vertexInformation; // [vertexCount]
|
||||
|
||||
Vector3 *normalInformation; // [vertexCount]
|
||||
};
|
||||
|
||||
class RwMaterialData : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
u32 unk1;
|
||||
u8 R;
|
||||
u8 G;
|
||||
u8 B;
|
||||
u8 A;
|
||||
u32 unk2;
|
||||
u32 textureCount;
|
||||
float unkPosX;
|
||||
float unkPosY;
|
||||
float unkPosZ;
|
||||
};
|
||||
|
||||
class RwTextureData : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
u16 textureFilterModeFlags;
|
||||
u16 unk;
|
||||
};
|
||||
|
||||
class RwString : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
~RwString() { delete[] text; }
|
||||
char *text;
|
||||
};
|
||||
|
||||
class RwTextureExtension : public RwSectionHeader
|
||||
{
|
||||
// May contain Sky Mipmap Val
|
||||
};
|
||||
|
||||
class RwTexture : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
RwTextureData data;
|
||||
RwString textureName;
|
||||
RwString textureAlphaName;
|
||||
RwTextureExtension extension;
|
||||
};
|
||||
|
||||
class RwMaterialExtension : public RwSectionHeader
|
||||
{
|
||||
// meant to be void.. don't ask
|
||||
};
|
||||
|
||||
class RwMaterial : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
~RwMaterial() { delete[] textures; }
|
||||
RwMaterialData data;
|
||||
RwTexture *textures;
|
||||
RwMaterialExtension extension;
|
||||
};
|
||||
|
||||
class RwMaterialListData : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
~RwMaterialListData() { delete[] arrayOfUnks; }
|
||||
u32 materialCount;
|
||||
u32 *arrayOfUnks; // Filled with '-1's, [materialCount] - it wasn't mentioned in docs.
|
||||
};
|
||||
|
||||
class RwMaterialList : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
~RwMaterialList() { delete[] materials; }
|
||||
RwMaterialListData data;
|
||||
RwMaterial *materials;
|
||||
};
|
||||
|
||||
class RwGeometryListVertexInfoChunk
|
||||
{
|
||||
public:
|
||||
u32 vertex1;
|
||||
};
|
||||
|
||||
class RwGeometryListInfoChunk
|
||||
{
|
||||
public:
|
||||
~RwGeometryListInfoChunk() { delete vertexInformation; }
|
||||
u32 faceIndex;
|
||||
u32 materialIndex;
|
||||
|
||||
RwGeometryListVertexInfoChunk *vertexInformation; // [faceIndex]
|
||||
};
|
||||
|
||||
class RwMaterialSplit
|
||||
{
|
||||
public:
|
||||
~RwMaterialSplit() { delete splitInformation; }
|
||||
class Header
|
||||
{
|
||||
public:
|
||||
u32 triangleStrip;
|
||||
u32 splitCount;
|
||||
u32 faceCount;
|
||||
} header;
|
||||
|
||||
RwGeometryListInfoChunk *splitInformation; // [splitCount]
|
||||
};
|
||||
|
||||
class RwGeometryExtension : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
RwMaterialSplit materialSplit;
|
||||
};
|
||||
|
||||
class RwGeometry : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
RwGeometryData data;
|
||||
RwMaterialList materialList;
|
||||
RwGeometryExtension extension;
|
||||
};
|
||||
// ---
|
||||
|
||||
// Section: Geometry List
|
||||
class RwGeometryListData : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
u32 geometryCount;
|
||||
};
|
||||
|
||||
class RwGeometryList : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
~RwGeometryList() { delete[] geometries; }
|
||||
RwGeometryListData data;
|
||||
RwGeometry *geometries;
|
||||
};
|
||||
// ---
|
||||
|
||||
// Section: Atomic
|
||||
class RwAtomicData : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
u32 frameNumber;
|
||||
u32 geometryNumber;
|
||||
u32 unk1;
|
||||
u32 unk2;
|
||||
};
|
||||
|
||||
class RwAtomic : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
RwAtomicData data;
|
||||
};
|
||||
// ---
|
||||
|
||||
// Section: Clump
|
||||
class RwClumpData : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
u32 objectCount;
|
||||
u32 unk1;
|
||||
u32 unk2;
|
||||
};
|
||||
|
||||
class RwClump : public RwSectionHeader
|
||||
{
|
||||
public:
|
||||
RwClumpData data;
|
||||
RwFrameList frameList;
|
||||
RwGeometryList geometryList;
|
||||
RwAtomic atomic; //multiple?? but how many
|
||||
};
|
||||
// ---
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_MD2_LOADER_
|
||||
#define _TYRA_MD2_LOADER_
|
||||
|
||||
#include "../models/md2_model.hpp"
|
||||
#include <stdio.h>
|
||||
|
||||
// magic number "IDP2" or 844121161
|
||||
#define MD2_IDENT (('2' << 24) + ('P' << 16) + ('D' << 8) + 'I')
|
||||
|
||||
// model version
|
||||
#define MD2_VERSION 8
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ident; // magic number. must be equal to "IDP2"
|
||||
int version; // md2 version. must be equal to 8
|
||||
|
||||
int skinwidth; // width of the texture
|
||||
int skinheight; // height of the texture
|
||||
int framesize; // size of one frame in bytes
|
||||
|
||||
int num_skins; // number of textures
|
||||
int num_xyz; // number of vertices
|
||||
int num_st; // number of texture coordinates
|
||||
int num_tris; // number of triangles
|
||||
int num_glcmds; // number of opengl commands
|
||||
int num_frames; // total number of frames
|
||||
|
||||
int ofs_skins; // offset to skin names (64 bytes each)
|
||||
int ofs_st; // offset to s-t texture coordinates
|
||||
int ofs_tris; // offset to triangles
|
||||
int ofs_frames; // offset to frame data
|
||||
int ofs_glcmds; // offset to opengl commands
|
||||
int ofs_end; // offset to end of file
|
||||
|
||||
} md2_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char v[3]; // compressed vertex (x, y, z) coordinates
|
||||
unsigned char lightnormalindex; // index to a normal vector for the lighting
|
||||
|
||||
} mvertex_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float scale[3]; // scale values
|
||||
float translate[3]; // translation vector
|
||||
char name[16]; // frame name
|
||||
mvertex_t verts[1]; // first vertex of this frame
|
||||
|
||||
} frame_t;
|
||||
|
||||
typedef float vec3_t[3];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short index_xyz[3]; // indexes to triangle's vertices
|
||||
short index_st[3]; // indexes to vertices' texture coorinates
|
||||
} triangle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short s;
|
||||
short t;
|
||||
} texCoord_t;
|
||||
|
||||
/** Class responsible for loading&parsing Quake's II ".md2" 3D files */
|
||||
class MD2Loader
|
||||
{
|
||||
|
||||
public:
|
||||
MD2Loader();
|
||||
~MD2Loader();
|
||||
|
||||
void load(MD2Model *o_result, char *t_fileName, float t_scale);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_OBJ_LOADER_
|
||||
#define _TYRA_OBJ_LOADER_
|
||||
|
||||
#include "../models/obj_model.hpp"
|
||||
#include <stdio.h>
|
||||
|
||||
/** Class responsible for loading&parsing .obj 3D files */
|
||||
class ObjLoader
|
||||
{
|
||||
|
||||
public:
|
||||
ObjLoader();
|
||||
~ObjLoader();
|
||||
|
||||
void load(ObjModel *o_result, char *t_fileName, float t_scale);
|
||||
|
||||
private:
|
||||
void setObjDataQuantities(FILE *t_file, ObjModel *t_result);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_AUDIO_LISTENER_
|
||||
#define _TYRA_AUDIO_LISTENER_
|
||||
|
||||
class AudioListener
|
||||
{
|
||||
|
||||
public:
|
||||
virtual ~AudioListener(){};
|
||||
virtual void onAudioTick() = 0;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_DFF_MODEL_
|
||||
#define _TYRA_DFF_MODEL_
|
||||
|
||||
#include <tamtypes.h>
|
||||
#include <math3d.h>
|
||||
#include "../loaders/dff_structure.hpp"
|
||||
#include "./math/vector3.hpp"
|
||||
|
||||
/** Class which have common types for all 3D objects */
|
||||
class DffModel
|
||||
{
|
||||
|
||||
public:
|
||||
DffModel();
|
||||
~DffModel();
|
||||
|
||||
u32 getDrawData(u32 splitIndex, VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, Vector3 &t_cameraPos, float t_scale, u8 t_shouldBeBackfaceCulled);
|
||||
RwClump clump;
|
||||
|
||||
private:
|
||||
void fillNextFace(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, u8 geometry, u32 t_getI, u32 t_setI);
|
||||
u8 isMemoryAllocated;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_LIGHT_BULB_
|
||||
#define _TYRA_LIGHT_BULB_
|
||||
|
||||
#include "math/vector3.hpp"
|
||||
#include <tamtypes.h>
|
||||
|
||||
struct LightBulb
|
||||
{
|
||||
Vector3 position;
|
||||
u16 intensity;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_MATRIX_
|
||||
#define _TYRA_MATRIX_
|
||||
|
||||
#include "vector3.hpp"
|
||||
#include "../screen_settings.hpp"
|
||||
|
||||
/** https://en.wikipedia.org/wiki/Matrix_(mathematics) */
|
||||
class Matrix
|
||||
{
|
||||
|
||||
public:
|
||||
float data[16];
|
||||
|
||||
Matrix(float m11, float m12, float m13, float m14,
|
||||
float m21, float m22, float m23, float m24,
|
||||
float m31, float m32, float m33, float m34,
|
||||
float m41, float m42, float m43, float m44);
|
||||
Matrix(const Matrix &v);
|
||||
Matrix operator*(Matrix &v);
|
||||
Matrix();
|
||||
~Matrix();
|
||||
|
||||
void lookAt(Vector3 &t_up, Vector3 &t_position, Vector3 &t_target);
|
||||
void identity();
|
||||
void makeZRotation(float t_radians);
|
||||
void translate(float t_x, float t_y, float t_z);
|
||||
void setPerspective(ScreenSettings &screen);
|
||||
void print();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_PLANE_
|
||||
#define _TYRA_PLANE_
|
||||
|
||||
#include "vector3.hpp"
|
||||
|
||||
/** https://en.wikipedia.org/wiki/Plane_(geometry) */
|
||||
class Plane
|
||||
{
|
||||
|
||||
public:
|
||||
Vector3 normal;
|
||||
float distance;
|
||||
|
||||
Plane();
|
||||
Plane(Vector3 &a, Vector3 &b, Vector3 &c);
|
||||
~Plane();
|
||||
|
||||
void update(Vector3 &a, Vector3 &b, Vector3 &c);
|
||||
inline float distanceTo(Vector3 &t_vec) { return this->distance + this->normal.innerProduct(t_vec); }
|
||||
void print();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_POINT_
|
||||
#define _TYRA_POINT_
|
||||
|
||||
/** https://en.wikipedia.org/wiki/Point_(geometry) */
|
||||
class Point
|
||||
{
|
||||
|
||||
public:
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
float xy[2] __attribute__((__aligned__(16)));
|
||||
};
|
||||
|
||||
Point(float x, float y);
|
||||
Point();
|
||||
~Point();
|
||||
|
||||
void set(float x, float y);
|
||||
void print();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_VECTOR3_
|
||||
#define _TYRA_VECTOR3_
|
||||
|
||||
#include <tamtypes.h>
|
||||
|
||||
class Math; // Forward definition
|
||||
|
||||
/** https://en.wikipedia.org/wiki/Vector_(mathematics_and_physics) */
|
||||
class Vector3
|
||||
{
|
||||
|
||||
public:
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
float xyz[3] __attribute__((__aligned__(16)));
|
||||
};
|
||||
|
||||
Vector3(float x, float y, float z);
|
||||
Vector3(const Vector3 &v);
|
||||
Vector3();
|
||||
~Vector3();
|
||||
|
||||
Vector3 operator+(Vector3 v);
|
||||
Vector3 operator-(const Vector3 &v);
|
||||
Vector3 operator*(Vector3 &v);
|
||||
Vector3 operator*(float t);
|
||||
Vector3 operator/(float t);
|
||||
Vector3 operator-(void);
|
||||
|
||||
static u8 shouldBeBackfaceCulled(const Vector3 *t_cameraPos, const Vector3 *v0, const Vector3 *v1, const Vector3 *v2);
|
||||
u8 collidesSquare(Vector3 &t_min, Vector3 &t_max);
|
||||
u8 isOnSquare(Vector3 &t_min, Vector3 &t_max);
|
||||
float length();
|
||||
void normalize();
|
||||
void setByLerp(const Vector3 &v1, const Vector3 &v2, const float t_interp);
|
||||
float innerProduct(Vector3 &v);
|
||||
void set(Vector3 &v);
|
||||
void set(float x, float y, float z);
|
||||
void copy(Vector3 &v);
|
||||
float distanceTo(Vector3 &v);
|
||||
void print();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_MD2_MODEL_
|
||||
#define _TYRA_MD2_MODEL_
|
||||
|
||||
#include <tamtypes.h>
|
||||
#include <math3d.h>
|
||||
#include "math/vector3.hpp"
|
||||
#include "math/point.hpp"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 startFrame;
|
||||
u32 endFrame;
|
||||
float speed;
|
||||
float interpolation;
|
||||
u32 animType;
|
||||
u32 currentFrame;
|
||||
u32 nextFrame;
|
||||
} MD2AnimState;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16 verticeIndexes[3];
|
||||
u16 coordIndexes[3];
|
||||
} MD2Triangle;
|
||||
|
||||
/** Class which have common types for all 3D objects */
|
||||
class MD2Model
|
||||
{
|
||||
|
||||
public:
|
||||
u32 verticesPerFrameCount, framesCount, coordinatesCount, trianglesCount;
|
||||
Vector3 *vertices __attribute__((aligned(16)));
|
||||
Point *coordinates;
|
||||
u32 *normalIndexes;
|
||||
MD2Triangle *triangles;
|
||||
MD2AnimState animState;
|
||||
/** File name without extension */
|
||||
char *filename;
|
||||
MD2Model(char *t_md2File);
|
||||
~MD2Model();
|
||||
u32 getCurrentFrameData(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, Vector3 &t_cameraPos, float t_scale, u8 t_shouldBeBackfaceCulled);
|
||||
void allocateMemory();
|
||||
|
||||
private:
|
||||
Vector3 calcVector;
|
||||
Vector3 calc3Vectors[3];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_OBJECT3D_
|
||||
#define _TYRA_OBJECT3D_
|
||||
|
||||
#include "math/vector3.hpp"
|
||||
#include "math/plane.hpp"
|
||||
#include "mesh_spec.hpp"
|
||||
#include "obj_model.hpp"
|
||||
#include "dff_model.hpp"
|
||||
#include "md2_model.hpp"
|
||||
#include <tamtypes.h>
|
||||
#include <draw_types.h>
|
||||
|
||||
/** Class which have common types for all 3D objects */
|
||||
class Mesh
|
||||
{
|
||||
|
||||
public:
|
||||
Vector3 position, rotation;
|
||||
u8 shouldBeLighted, shouldBeBackfaceCulled, shouldBeFrustumCulled;
|
||||
|
||||
MeshSpec *spec;
|
||||
MD2Model *md2;
|
||||
ObjModel *obj;
|
||||
DffModel *dff;
|
||||
float scale;
|
||||
color_t color;
|
||||
Vector3 boxVertices[8];
|
||||
|
||||
Mesh();
|
||||
~Mesh();
|
||||
|
||||
void loadObj(char *t_subfolder, char *t_objFile, Vector3 &t_initPos, float t_scale);
|
||||
void setObj(Vector3 &t_initPos, ObjModel *t_objModel, MeshSpec *t_spec);
|
||||
void loadDff(char *t_subfolder, char *t_dffFile, Vector3 &t_initPos, float t_scale);
|
||||
void setDff(Vector3 &t_initPos, DffModel *t_dffModel, MeshSpec *t_spec);
|
||||
void loadMD2(char *t_subfolder, char *t_md2File, Vector3 &t_initPos, float t_scale);
|
||||
void getMinMax(Vector3 *t_min, Vector3 *t_max);
|
||||
void playAnimation(u32 t_startFrame, u32 t_endFrame);
|
||||
u32 getVertexCount();
|
||||
void setAnimSpeed(float t_value);
|
||||
u32 getDrawData(u32 splitIndex, VECTOR *t_vertices, VECTOR *t_normals, VECTOR *t_coordinates, VECTOR *t_colors, Vector3 &t_cameraPos);
|
||||
u8 isInFrustum(Plane *t_frustumPlanes);
|
||||
|
||||
u8 isMd2Loaded, isObjLoaded, isDffLoaded, isSpecInitialized;
|
||||
|
||||
private:
|
||||
void setDefaultWrapSettings(texwrap_t &t_wrapSettings);
|
||||
u32 verticesCount;
|
||||
Vector3 *vertices;
|
||||
void loadTextures(char *t_subfolder, char *t_extension);
|
||||
void computeBoundingBox();
|
||||
void setVerticesReference(u32 t_verticesCount, Vector3 *t_verticesRef);
|
||||
void createSpecIfNotCreated();
|
||||
void setDefaultColor();
|
||||
void getFarthestVertex(Vector3 *o_result, int t_offset);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_OBJECT3D_SPEC_
|
||||
#define _TYRA_OBJECT3D_SPEC_
|
||||
|
||||
#include "math/vector3.hpp"
|
||||
#include "./texture.hpp"
|
||||
#include <tamtypes.h>
|
||||
#include <draw_buffers.h>
|
||||
#include <draw_sampling.h>
|
||||
|
||||
/** Class which contain 3D object specification */
|
||||
class MeshSpec
|
||||
{
|
||||
|
||||
public:
|
||||
texbuffer_t textureBuffer;
|
||||
clutbuffer_t clut;
|
||||
lod_t lod;
|
||||
|
||||
MeshSpec();
|
||||
~MeshSpec();
|
||||
void allocateTextureBuffer(u16 t_width, u16 t_height);
|
||||
void deallocateTextureBuffer();
|
||||
void allocateMemory();
|
||||
void setupLodAndClut();
|
||||
Texture *textures;
|
||||
|
||||
private:
|
||||
u8 isTextureVRAMAllocated;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_OBJ_MODEL_
|
||||
#define _TYRA_OBJ_MODEL_
|
||||
|
||||
#include <tamtypes.h>
|
||||
#include <math3d.h>
|
||||
#include "math/vector3.hpp"
|
||||
|
||||
/** Class which have common types for all 3D objects */
|
||||
class ObjModel
|
||||
{
|
||||
|
||||
public:
|
||||
u32 verticesCount, coordinatesCount, normalsCount, facesCount;
|
||||
Vector3 *vertices __attribute__((aligned(16))),
|
||||
*coordinates __attribute__((aligned(16))),
|
||||
*normals __attribute__((aligned(16)));
|
||||
u32 *verticeFaces, *coordinateFaces, *normalFaces;
|
||||
|
||||
/** File name without extension */
|
||||
char *filename;
|
||||
|
||||
ObjModel(char *t_objFile);
|
||||
~ObjModel();
|
||||
u32 getDrawData(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, Vector3 &t_cameraPos, float t_scale, u8 t_shouldBeBackfaceCulled);
|
||||
void allocateMemory();
|
||||
|
||||
private:
|
||||
void fillNextFace(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, u32 t_getI, u32 t_setI);
|
||||
u8 isMemoryAllocated;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_RENDER_DATA_
|
||||
#define _TYRA_RENDER_DATA_
|
||||
|
||||
#include "light_bulb.hpp"
|
||||
#include <draw_primitives.h>
|
||||
#include "math/matrix.hpp"
|
||||
#include "math/plane.hpp"
|
||||
|
||||
struct RenderData
|
||||
{
|
||||
LightBulb *bulbs;
|
||||
u16 bulbsCount;
|
||||
/** Camera (lookAt) */
|
||||
Matrix *worldView;
|
||||
/** Perspective projection */
|
||||
Matrix *perspective;
|
||||
Vector3 *cameraPosition;
|
||||
Plane *frustumPlanes;
|
||||
prim_t *prim;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_SCREEN_SETTINGS_
|
||||
#define _TYRA_SCREEN_SETTINGS_
|
||||
|
||||
struct ScreenSettings
|
||||
{
|
||||
float fov;
|
||||
float width;
|
||||
float height;
|
||||
float aspectRatio;
|
||||
float nearPlaneDist;
|
||||
float farPlaneDist;
|
||||
/** change it to 4096.0F to check out frustum culling! 😎 */
|
||||
float projectionScale;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_TEXTURE_
|
||||
#define _TYRA_TEXTURE_
|
||||
|
||||
#include <tamtypes.h>
|
||||
#include <draw_sampling.h>
|
||||
|
||||
struct Texture
|
||||
{
|
||||
u32 id;
|
||||
unsigned char *data;
|
||||
texwrap_t wrapSettings;
|
||||
char *name;
|
||||
u8 width, height;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_AUDIO_
|
||||
#define _TYRA_AUDIO_
|
||||
|
||||
#include <tamtypes.h>
|
||||
#include <stdio.h>
|
||||
#include <audsrv.h>
|
||||
#include <kernel.h>
|
||||
#include "../models/audio_listener.hpp"
|
||||
|
||||
#define STACK_SIZE 8 * 1024
|
||||
|
||||
/** Class responsible for audio playing */
|
||||
class Audio
|
||||
{
|
||||
|
||||
public:
|
||||
Audio();
|
||||
~Audio();
|
||||
|
||||
u8 isTrackDone;
|
||||
ee_sema_t sema;
|
||||
int fillbufferSema;
|
||||
|
||||
void init(u32 t_listenersAmount);
|
||||
void play();
|
||||
void stop();
|
||||
void loadSong(char *t_filename);
|
||||
void unloadSong();
|
||||
void setVolume(u8 t_volume);
|
||||
void addListener(AudioListener *t_listener);
|
||||
void startThread();
|
||||
|
||||
private:
|
||||
void work();
|
||||
static void audioThread();
|
||||
u8 isInitialized, shouldPlay, songLoaded, isVolumeSet;
|
||||
|
||||
ee_thread_t audioThreadAttr;
|
||||
u8 audioThreadStack[STACK_SIZE] ALIGNED(16);
|
||||
int audioThreadId;
|
||||
|
||||
AudioListener **listeners;
|
||||
u32 listenersAmount;
|
||||
u32 addedListeners;
|
||||
void initSema();
|
||||
void loadModules();
|
||||
void initAUDSRV();
|
||||
|
||||
int ret, played;
|
||||
char chunk[2048];
|
||||
FILE *wav;
|
||||
audsrv_fmt_t format;
|
||||
static int fillbuffer(void *arg);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_CAMERA_BASE_
|
||||
#define _TYRA_CAMERA_BASE_
|
||||
|
||||
#include "../models/math/plane.hpp"
|
||||
#include "../models/math/matrix.hpp"
|
||||
#include "../models/math/vector3.hpp"
|
||||
#include "../models/screen_settings.hpp"
|
||||
|
||||
/** Class responsible for frustum culling */
|
||||
class CameraBase
|
||||
{
|
||||
|
||||
public:
|
||||
CameraBase(ScreenSettings *t_screen, Vector3 *t_position, Vector3 *t_up, Vector3 *t_unitCirclePosition);
|
||||
virtual ~CameraBase(){};
|
||||
|
||||
void setScreen();
|
||||
void updatePlanes(Vector3 t_target);
|
||||
Plane planes[6];
|
||||
Matrix worldView;
|
||||
|
||||
protected:
|
||||
ScreenSettings *screen;
|
||||
|
||||
private:
|
||||
Vector3 *position2, *up2, *unitCirclePosition2;
|
||||
float farPlaneDist, nearPlaneDist, nearHeight, nearWidth, farHeight, farWidth;
|
||||
Vector3 ftl, ftr, fbl, fbr, ntl, ntr, nbl, nbr;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_GIF_SENDER_
|
||||
#define _TYRA_GIF_SENDER_
|
||||
|
||||
#include <tamtypes.h>
|
||||
#include <draw_buffers.h>
|
||||
#include <draw_types.h>
|
||||
#include <draw_primitives.h>
|
||||
#include <math3d.h>
|
||||
#include <packet.h>
|
||||
#include "../models/mesh.hpp"
|
||||
#include "../models/math/matrix.hpp"
|
||||
#include "../models/screen_settings.hpp"
|
||||
#include "../models/light_bulb.hpp"
|
||||
#include "../models/render_data.hpp"
|
||||
|
||||
/** Class responsible for sending data packets via GIF (PATH3) */
|
||||
class GifSender
|
||||
{
|
||||
|
||||
public:
|
||||
GifSender(u32 t_packetSize, ScreenSettings *t_screen);
|
||||
~GifSender();
|
||||
|
||||
void initPacket(u8 context);
|
||||
void addObjects(RenderData *t_renderData, Mesh **t_objects3D, u32 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||
void addClear(zbuffer_t *t_zBuffer);
|
||||
void sendPacket();
|
||||
void sendClear(zbuffer_t *t_zBuffer);
|
||||
static void sendTexture(Texture &texture, texbuffer_t *t_texBuffer);
|
||||
|
||||
private:
|
||||
xyz_t *xyz;
|
||||
color_t *rgbaq;
|
||||
texel_t *st;
|
||||
u8 isAnyObjectAdded;
|
||||
ScreenSettings *screen;
|
||||
u64 *dw;
|
||||
qword_t *q, *dmatag;
|
||||
packet_t *packets[2];
|
||||
packet_t *currentPacket;
|
||||
u8 packetsCount;
|
||||
int packetSize;
|
||||
float halfScreenW, halfScreenH;
|
||||
MATRIX localWorld, localScreen, localLight;
|
||||
|
||||
u32 calc3DObject(Matrix t_perspective, Mesh &t_mesh, RenderData *t_renderData, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||
void convertCalcs(u32 t_vertCount, VECTOR *t_vertices, VECTOR *t_colors, VECTOR *t_sts, u8 t_alpha);
|
||||
void addCurrentCalcs(u32 &t_vertexCount);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_LIGHT_
|
||||
#define _TYRA_LIGHT_
|
||||
|
||||
#include <math3d.h>
|
||||
#include <tamtypes.h>
|
||||
#include "../models/math/vector3.hpp"
|
||||
#include "../models/light_bulb.hpp"
|
||||
|
||||
class Light
|
||||
{
|
||||
|
||||
public:
|
||||
Light();
|
||||
~Light();
|
||||
|
||||
static u16 getLightsCount(u32 t_bulbsCount);
|
||||
static void calculateLight(VECTOR *t_lightDirections, VECTOR *t_lightColors, int *t_lightTypes, LightBulb *t_bulbs, u32 t_bulbsCount, Vector3 t_objPosition);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_PAD_
|
||||
#define _TYRA_PAD_
|
||||
|
||||
#include <tamtypes.h>
|
||||
#include <libpad.h>
|
||||
|
||||
/** Class responsible for player pad */
|
||||
class Pad
|
||||
{
|
||||
|
||||
public:
|
||||
u8 isCrossClicked, isSquareClicked, isTriangleClicked, isCircleClicked;
|
||||
u8 isDpadUpPressed, isDpadDownPressed, isDpadLeftPressed, isDpadRightPressed;
|
||||
u8 lJoyH, lJoyV, rJoyH, rJoyV;
|
||||
|
||||
Pad();
|
||||
~Pad();
|
||||
void update();
|
||||
|
||||
private:
|
||||
char padBuf[256] __attribute__((aligned(64)));
|
||||
char actAlign[6];
|
||||
int actuators, ret, port, slot;
|
||||
padButtonStatus buttons;
|
||||
u32 padData, oldPad, newPad;
|
||||
|
||||
void reset();
|
||||
void loadModules();
|
||||
int waitPadReady();
|
||||
int initPad();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_RENDERER_
|
||||
#define _TYRA_RENDERER_
|
||||
|
||||
#include <draw_buffers.h>
|
||||
#include <draw_primitives.h>
|
||||
#include <packet.h>
|
||||
#include "gif_sender.hpp"
|
||||
#include "vif_sender.hpp"
|
||||
#include "../models/math/plane.hpp"
|
||||
#include "../models/screen_settings.hpp"
|
||||
#include "../models/render_data.hpp"
|
||||
|
||||
/** Class responsible for intializing draw env, textures and buffers */
|
||||
class Renderer
|
||||
{
|
||||
|
||||
public:
|
||||
Renderer(u32 t_packetSize, ScreenSettings *t_screen);
|
||||
~Renderer();
|
||||
|
||||
framebuffer_t frameBuffers[2];
|
||||
u8 context;
|
||||
zbuffer_t zBuffer;
|
||||
prim_t prim;
|
||||
|
||||
/** PATH3 Many + lighting */
|
||||
void drawByPath3(Mesh **t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||
/** PATH3 Single + lighting */
|
||||
void drawByPath3(Mesh *t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||
/** PATH3 Many */
|
||||
void drawByPath3(Mesh **t_meshes, u16 t_amount);
|
||||
/** PATH3 Single */
|
||||
void drawByPath3(Mesh *t_mesh);
|
||||
|
||||
/** PATH1 Many + lighting */
|
||||
void draw(Mesh **t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||
/** PATH1 Single + lighting */
|
||||
void draw(Mesh *t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||
/** PATH1 Many */
|
||||
void draw(Mesh **t_meshes, u16 t_amount);
|
||||
/** PATH1 Single */
|
||||
void draw(Mesh *t_mesh);
|
||||
|
||||
void setCameraDefinitions(Matrix *t_worldView, Vector3 *t_cameraPos, Plane *t_planes);
|
||||
|
||||
void endFrame(float fps);
|
||||
|
||||
private:
|
||||
void changeTexture(Mesh *t_mesh, u8 t_textureIndex);
|
||||
void flipBuffers();
|
||||
void beginFrameIfNeeded();
|
||||
u8 isFrameEmpty;
|
||||
Matrix perspective;
|
||||
RenderData renderData;
|
||||
|
||||
u32 lastTextureId;
|
||||
GifSender *gifSender;
|
||||
VifSender *vifSender;
|
||||
packet_t *flipPacket;
|
||||
void allocateBuffers(float t_screenW, float t_screenH);
|
||||
void initDrawingEnv(float t_screenW, float t_screenH);
|
||||
void setPrim();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_TIMER_
|
||||
#define _TYRA_TIMER_
|
||||
|
||||
#include <tamtypes.h>
|
||||
|
||||
/** Class responsible for fps counting */
|
||||
class Timer
|
||||
{
|
||||
|
||||
public:
|
||||
Timer();
|
||||
~Timer();
|
||||
|
||||
u32 getTimeDelta();
|
||||
void primeTimer();
|
||||
float getFPS();
|
||||
|
||||
private:
|
||||
u32 lastTime, time, change;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_VIF_SENDER_
|
||||
#define _TYRA_VIF_SENDER_
|
||||
|
||||
#include <tamtypes.h>
|
||||
#include "../models/render_data.hpp"
|
||||
#include "../models/light_bulb.hpp"
|
||||
#include "../models/mesh.hpp"
|
||||
#include "../models/math/matrix.hpp"
|
||||
#include "../models/math/vector3.hpp"
|
||||
#include "vu1.hpp"
|
||||
|
||||
/** Class responsible for sending 3D objects via VIF (PATH 1) */
|
||||
class VifSender
|
||||
{
|
||||
|
||||
public:
|
||||
VifSender();
|
||||
~VifSender();
|
||||
|
||||
// TODO refactor
|
||||
void drawMesh(RenderData *t_renderData, Matrix t_perspective, u32 vertCount2, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, VECTOR *colors, Mesh *t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||
|
||||
private:
|
||||
void drawVertices(Mesh *t_mesh, u32 t_start, u32 t_end, VECTOR *t_vertices, VECTOR *t_colors, VECTOR *t_coordinates, prim_t *t_prim);
|
||||
|
||||
MATRIX localWorld, localScreen;
|
||||
VECTOR position, rotation;
|
||||
u32 vertCount;
|
||||
VU1 vu1;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_VU1_
|
||||
#define _TYRA_VU1_
|
||||
|
||||
#include "../models/math/matrix.hpp"
|
||||
#include <draw_buffers.h>
|
||||
#include <tamtypes.h>
|
||||
#include <draw_primitives.h>
|
||||
#include <packet.h>
|
||||
#include <math3d.h>
|
||||
|
||||
const u32 VIF_BUFFER_SIZE = 48 * 1024;
|
||||
|
||||
typedef struct VU1BuildList
|
||||
{
|
||||
u8 isBuilding;
|
||||
void *offset;
|
||||
void *kickBuffer;
|
||||
u32 dmaSize;
|
||||
u32 dmaSizeAll;
|
||||
u32 dmaDestination;
|
||||
} VU1BuildList;
|
||||
|
||||
/** Class responsible for managing VU1 micro programs */
|
||||
class VU1
|
||||
{
|
||||
|
||||
public:
|
||||
VU1();
|
||||
~VU1();
|
||||
|
||||
static void uploadProgram(int t_dest, u32 *t_start, u32 *t_end);
|
||||
void createList();
|
||||
void sendSingleRefList(int t_destAddress, void *t_data, int t_quadSize);
|
||||
void addListBeginning();
|
||||
void continueList();
|
||||
void addReferenceList(u32 t_offset, void *t_data, u32 t_size, u8 t_useTops);
|
||||
void addFloat(float v);
|
||||
void add32(u32 v);
|
||||
void add64(u64 v);
|
||||
void add128(u64 v1, u64 v2);
|
||||
void addListEnding();
|
||||
void addStartProgram();
|
||||
void addContinueProgram();
|
||||
void sendList();
|
||||
void addDoubleBufferSetting();
|
||||
void addFlush();
|
||||
|
||||
private:
|
||||
u8 isDoubleBufferSet;
|
||||
void checkDataAlignment(void *data);
|
||||
VU1BuildList buildList;
|
||||
char dmaBuffer1[VIF_BUFFER_SIZE] __attribute__((aligned(16)));
|
||||
char dmaBuffer2[VIF_BUFFER_SIZE] __attribute__((aligned(16)));
|
||||
void *currentBuffer;
|
||||
u32 switchBuffer;
|
||||
static u32 countProgramSize(u32 *t_start, u32 *t_end);
|
||||
void checkList();
|
||||
inline s32 AddUnpack(int format, int addr, int num, int usetops = 0, int nosign = 1, int masking = 0)
|
||||
{
|
||||
return (s32)((0x60 << 24) + (format << 24) + (masking << 28) + (usetops << 15) +
|
||||
(nosign << 14) + (num << 16) + addr);
|
||||
}
|
||||
};
|
||||
|
||||
#define DMA_REF_TAG(ADDR, COUNT) ((((unsigned long)ADDR) << 32) | (0x3 << 28) | COUNT)
|
||||
#define DMA_CNT_TAG(COUNT) (((unsigned long)(0x1) << 28) | COUNT)
|
||||
#define DMA_END_TAG(COUNT) (((unsigned long)(0x7) << 28) | COUNT)
|
||||
#define VIF_NOP 0x00
|
||||
#define VIF_STCYL 0x01
|
||||
#define VIF_OFFSET 0x02
|
||||
#define VIF_BASE 0x03
|
||||
#define VIF_FLUSH 0x11
|
||||
#define VIF_MSCAL 0x14
|
||||
#define VIF_MSCNT 0x17
|
||||
#define VIF_MPG 0x4A
|
||||
#define V4_32 0xC
|
||||
#define VIF_UNPACK 0x60
|
||||
#define U128(n) ((u128)(n))
|
||||
#define VIF_UNPACK_V4_32 (VIF_UNPACK | V4_32)
|
||||
#define VIF_CODE(CMD, NUM, IMMEDIATE) ((((unsigned int)(CMD)) << 24) | \
|
||||
(((unsigned int)(NUM)) << 16) | \
|
||||
((unsigned int)(IMMEDIATE)))
|
||||
#define GS_PRIM(PRIM, IIP, TME, FGE, ABE, AA1, FST, CTXT, FIX) U128((FIX << 10) | (CTXT << 9) | (FST << 8) | (AA1 << 7) | (ABE << 6) | (FGE << 5) | (TME << 4) | (IIP << 3) | (PRIM))
|
||||
#define GS_GIFTAG(NLOOP, EOP, PRE, PRIM, FLG, NREG) (((u64)(NREG) << 60) | ((u64)(FLG) << 58) | ((u64)(PRIM) << 47) | ((u64)(PRE) << 46) | (EOP << 15) | (NLOOP << 0))
|
||||
#define VU1_DMA_CHAN_TIMEOUT -1
|
||||
#define GS_GIFTAG_PACKED 0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_ANORMS_
|
||||
#define _TYRA_ANORMS_
|
||||
|
||||
const float ANORMS[162][3] = {
|
||||
{-0.525731f, 0.000000f, 0.850651f},
|
||||
{-0.442863f, 0.238856f, 0.864188f},
|
||||
{-0.295242f, 0.000000f, 0.955423f},
|
||||
{-0.309017f, 0.500000f, 0.809017f},
|
||||
{-0.162460f, 0.262866f, 0.951056f},
|
||||
{0.000000f, 0.000000f, 1.000000f},
|
||||
{0.000000f, 0.850651f, 0.525731f},
|
||||
{-0.147621f, 0.716567f, 0.681718f},
|
||||
{0.147621f, 0.716567f, 0.681718f},
|
||||
{0.000000f, 0.525731f, 0.850651f},
|
||||
{0.309017f, 0.500000f, 0.809017f},
|
||||
{0.525731f, 0.000000f, 0.850651f},
|
||||
{0.295242f, 0.000000f, 0.955423f},
|
||||
{0.442863f, 0.238856f, 0.864188f},
|
||||
{0.162460f, 0.262866f, 0.951056f},
|
||||
{-0.681718f, 0.147621f, 0.716567f},
|
||||
{-0.809017f, 0.309017f, 0.500000f},
|
||||
{-0.587785f, 0.425325f, 0.688191f},
|
||||
{-0.850651f, 0.525731f, 0.000000f},
|
||||
{-0.864188f, 0.442863f, 0.238856f},
|
||||
{-0.716567f, 0.681718f, 0.147621f},
|
||||
{-0.688191f, 0.587785f, 0.425325f},
|
||||
{-0.500000f, 0.809017f, 0.309017f},
|
||||
{-0.238856f, 0.864188f, 0.442863f},
|
||||
{-0.425325f, 0.688191f, 0.587785f},
|
||||
{-0.716567f, 0.681718f, -0.147621f},
|
||||
{-0.500000f, 0.809017f, -0.309017f},
|
||||
{-0.525731f, 0.850651f, 0.000000f},
|
||||
{0.000000f, 0.850651f, -0.525731f},
|
||||
{-0.238856f, 0.864188f, -0.442863f},
|
||||
{0.000000f, 0.955423f, -0.295242f},
|
||||
{-0.262866f, 0.951056f, -0.162460f},
|
||||
{0.000000f, 1.000000f, 0.000000f},
|
||||
{0.000000f, 0.955423f, 0.295242f},
|
||||
{-0.262866f, 0.951056f, 0.162460f},
|
||||
{0.238856f, 0.864188f, 0.442863f},
|
||||
{0.262866f, 0.951056f, 0.162460f},
|
||||
{0.500000f, 0.809017f, 0.309017f},
|
||||
{0.238856f, 0.864188f, -0.442863f},
|
||||
{0.262866f, 0.951056f, -0.162460f},
|
||||
{0.500000f, 0.809017f, -0.309017f},
|
||||
{0.850651f, 0.525731f, 0.000000f},
|
||||
{0.716567f, 0.681718f, 0.147621f},
|
||||
{0.716567f, 0.681718f, -0.147621f},
|
||||
{0.525731f, 0.850651f, 0.000000f},
|
||||
{0.425325f, 0.688191f, 0.587785f},
|
||||
{0.864188f, 0.442863f, 0.238856f},
|
||||
{0.688191f, 0.587785f, 0.425325f},
|
||||
{0.809017f, 0.309017f, 0.500000f},
|
||||
{0.681718f, 0.147621f, 0.716567f},
|
||||
{0.587785f, 0.425325f, 0.688191f},
|
||||
{0.955423f, 0.295242f, 0.000000f},
|
||||
{1.000000f, 0.000000f, 0.000000f},
|
||||
{0.951056f, 0.162460f, 0.262866f},
|
||||
{0.850651f, -0.525731f, 0.000000f},
|
||||
{0.955423f, -0.295242f, 0.000000f},
|
||||
{0.864188f, -0.442863f, 0.238856f},
|
||||
{0.951056f, -0.162460f, 0.262866f},
|
||||
{0.809017f, -0.309017f, 0.500000f},
|
||||
{0.681718f, -0.147621f, 0.716567f},
|
||||
{0.850651f, 0.000000f, 0.525731f},
|
||||
{0.864188f, 0.442863f, -0.238856f},
|
||||
{0.809017f, 0.309017f, -0.500000f},
|
||||
{0.951056f, 0.162460f, -0.262866f},
|
||||
{0.525731f, 0.000000f, -0.850651f},
|
||||
{0.681718f, 0.147621f, -0.716567f},
|
||||
{0.681718f, -0.147621f, -0.716567f},
|
||||
{0.850651f, 0.000000f, -0.525731f},
|
||||
{0.809017f, -0.309017f, -0.500000f},
|
||||
{0.864188f, -0.442863f, -0.238856f},
|
||||
{0.951056f, -0.162460f, -0.262866f},
|
||||
{0.147621f, 0.716567f, -0.681718f},
|
||||
{0.309017f, 0.500000f, -0.809017f},
|
||||
{0.425325f, 0.688191f, -0.587785f},
|
||||
{0.442863f, 0.238856f, -0.864188f},
|
||||
{0.587785f, 0.425325f, -0.688191f},
|
||||
{0.688191f, 0.587785f, -0.425325f},
|
||||
{-0.147621f, 0.716567f, -0.681718f},
|
||||
{-0.309017f, 0.500000f, -0.809017f},
|
||||
{0.000000f, 0.525731f, -0.850651f},
|
||||
{-0.525731f, 0.000000f, -0.850651f},
|
||||
{-0.442863f, 0.238856f, -0.864188f},
|
||||
{-0.295242f, 0.000000f, -0.955423f},
|
||||
{-0.162460f, 0.262866f, -0.951056f},
|
||||
{0.000000f, 0.000000f, -1.000000f},
|
||||
{0.295242f, 0.000000f, -0.955423f},
|
||||
{0.162460f, 0.262866f, -0.951056f},
|
||||
{-0.442863f, -0.238856f, -0.864188f},
|
||||
{-0.309017f, -0.500000f, -0.809017f},
|
||||
{-0.162460f, -0.262866f, -0.951056f},
|
||||
{0.000000f, -0.850651f, -0.525731f},
|
||||
{-0.147621f, -0.716567f, -0.681718f},
|
||||
{0.147621f, -0.716567f, -0.681718f},
|
||||
{0.000000f, -0.525731f, -0.850651f},
|
||||
{0.309017f, -0.500000f, -0.809017f},
|
||||
{0.442863f, -0.238856f, -0.864188f},
|
||||
{0.162460f, -0.262866f, -0.951056f},
|
||||
{0.238856f, -0.864188f, -0.442863f},
|
||||
{0.500000f, -0.809017f, -0.309017f},
|
||||
{0.425325f, -0.688191f, -0.587785f},
|
||||
{0.716567f, -0.681718f, -0.147621f},
|
||||
{0.688191f, -0.587785f, -0.425325f},
|
||||
{0.587785f, -0.425325f, -0.688191f},
|
||||
{0.000000f, -0.955423f, -0.295242f},
|
||||
{0.000000f, -1.000000f, 0.000000f},
|
||||
{0.262866f, -0.951056f, -0.162460f},
|
||||
{0.000000f, -0.850651f, 0.525731f},
|
||||
{0.000000f, -0.955423f, 0.295242f},
|
||||
{0.238856f, -0.864188f, 0.442863f},
|
||||
{0.262866f, -0.951056f, 0.162460f},
|
||||
{0.500000f, -0.809017f, 0.309017f},
|
||||
{0.716567f, -0.681718f, 0.147621f},
|
||||
{0.525731f, -0.850651f, 0.000000f},
|
||||
{-0.238856f, -0.864188f, -0.442863f},
|
||||
{-0.500000f, -0.809017f, -0.309017f},
|
||||
{-0.262866f, -0.951056f, -0.162460f},
|
||||
{-0.850651f, -0.525731f, 0.000000f},
|
||||
{-0.716567f, -0.681718f, -0.147621f},
|
||||
{-0.716567f, -0.681718f, 0.147621f},
|
||||
{-0.525731f, -0.850651f, 0.000000f},
|
||||
{-0.500000f, -0.809017f, 0.309017f},
|
||||
{-0.238856f, -0.864188f, 0.442863f},
|
||||
{-0.262866f, -0.951056f, 0.162460f},
|
||||
{-0.864188f, -0.442863f, 0.238856f},
|
||||
{-0.809017f, -0.309017f, 0.500000f},
|
||||
{-0.688191f, -0.587785f, 0.425325f},
|
||||
{-0.681718f, -0.147621f, 0.716567f},
|
||||
{-0.442863f, -0.238856f, 0.864188f},
|
||||
{-0.587785f, -0.425325f, 0.688191f},
|
||||
{-0.309017f, -0.500000f, 0.809017f},
|
||||
{-0.147621f, -0.716567f, 0.681718f},
|
||||
{-0.425325f, -0.688191f, 0.587785f},
|
||||
{-0.162460f, -0.262866f, 0.951056f},
|
||||
{0.442863f, -0.238856f, 0.864188f},
|
||||
{0.162460f, -0.262866f, 0.951056f},
|
||||
{0.309017f, -0.500000f, 0.809017f},
|
||||
{0.147621f, -0.716567f, 0.681718f},
|
||||
{0.000000f, -0.525731f, 0.850651f},
|
||||
{0.425325f, -0.688191f, 0.587785f},
|
||||
{0.587785f, -0.425325f, 0.688191f},
|
||||
{0.688191f, -0.587785f, 0.425325f},
|
||||
{-0.955423f, 0.295242f, 0.000000f},
|
||||
{-0.951056f, 0.162460f, 0.262866f},
|
||||
{-1.000000f, 0.000000f, 0.000000f},
|
||||
{-0.850651f, 0.000000f, 0.525731f},
|
||||
{-0.955423f, -0.295242f, 0.000000f},
|
||||
{-0.951056f, -0.162460f, 0.262866f},
|
||||
{-0.864188f, 0.442863f, -0.238856f},
|
||||
{-0.951056f, 0.162460f, -0.262866f},
|
||||
{-0.809017f, 0.309017f, -0.500000f},
|
||||
{-0.864188f, -0.442863f, -0.238856f},
|
||||
{-0.951056f, -0.162460f, -0.262866f},
|
||||
{-0.809017f, -0.309017f, -0.500000f},
|
||||
{-0.681718f, 0.147621f, -0.716567f},
|
||||
{-0.681718f, -0.147621f, -0.716567f},
|
||||
{-0.850651f, 0.000000f, -0.525731f},
|
||||
{-0.688191f, 0.587785f, -0.425325f},
|
||||
{-0.587785f, 0.425325f, -0.688191f},
|
||||
{-0.425325f, 0.688191f, -0.587785f},
|
||||
{-0.425325f, -0.688191f, -0.587785f},
|
||||
{-0.587785f, -0.425325f, -0.688191f},
|
||||
{-0.688191f, -0.587785f, -0.425325f}};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_DEBUG_
|
||||
#define _TYRA_DEBUG_
|
||||
|
||||
#include <tamtypes.h>
|
||||
#include <math3d.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define PRINT_LOG(TEXT) printf("LOG: " TEXT " (" __FILE__ ")\n")
|
||||
#define PRINT_ERR(TEXT) printf("---\n--- ---\n--- --- --- ERR: " TEXT " (" __FILE__ ")\n--- ---\n---\n")
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_MATH_
|
||||
#define _TYRA_MATH_
|
||||
|
||||
#include <tamtypes.h>
|
||||
#include <math3d.h>
|
||||
#include "../models/math/vector3.hpp"
|
||||
|
||||
class Vector3; // Forward definition
|
||||
|
||||
void manyVec3ToNative(VECTOR *t_result, Vector3 *t_vec, int t_amount, float t_fourthVal);
|
||||
void vec3ToNative(VECTOR t_result, Vector3 &t_vec, float t_fourthVal);
|
||||
|
||||
class Math
|
||||
{
|
||||
|
||||
public:
|
||||
const static float HALF_ANG2RAD = 3.14159265358979323846 / 360.0;
|
||||
const static float PI = 3.1415926535897932384626433832795F;
|
||||
const static float HALF_PI = 1.5707963267948966192313216916398F;
|
||||
static float cos(float x);
|
||||
static inline float sin(float x) { return cos(x - HALF_PI); };
|
||||
static float sqrt(float x);
|
||||
static float invSqrt(float x);
|
||||
|
||||
private:
|
||||
Math();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_STRING_
|
||||
#define _TYRA_STRING_
|
||||
|
||||
#include <tamtypes.h>
|
||||
|
||||
class String
|
||||
{
|
||||
|
||||
public:
|
||||
static char *createCopy(char *source);
|
||||
static u32 getLength(char *a);
|
||||
static char *createConcatenated(char *a, char *b);
|
||||
static char *createWithoutExtension(char *source);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/loaders/bmp_loader.hpp"
|
||||
|
||||
#include "../include/utils/debug.hpp"
|
||||
#include "../include/utils/string.hpp"
|
||||
#include <cstdlib>
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
BmpLoader::BmpLoader() {}
|
||||
|
||||
BmpLoader::~BmpLoader() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
/**
|
||||
* @param t_name Without extension. Example "skyfall2"
|
||||
* @param t_extension With dot and extension. Example ".BMP"
|
||||
*/
|
||||
void BmpLoader::load(Texture &o_texture, char *t_subfolder, char *t_name, char *t_extension)
|
||||
{
|
||||
char *t_path_part = String::createConcatenated(t_subfolder, t_name);
|
||||
char *t_path = String::createConcatenated(t_path_part, t_extension);
|
||||
delete[] t_path_part;
|
||||
|
||||
FILE *file = fopen(t_path, "rb");
|
||||
|
||||
if (file == NULL)
|
||||
PRINT_ERR("Failed to load .bmp file!");
|
||||
|
||||
unsigned char header[54];
|
||||
fread(header, sizeof(unsigned char), 54, file);
|
||||
|
||||
u32 width = *(u32 *)&header[18];
|
||||
u32 height = *(u32 *)&header[22];
|
||||
o_texture.id = rand() % 100000;
|
||||
o_texture.width = width;
|
||||
o_texture.height = height;
|
||||
o_texture.data = new unsigned char[width * height * 3];
|
||||
printf("BMPLoader - width: %d | height: %d\n", width, height);
|
||||
|
||||
u64 rowPadded = (width * 3 + 3) & (~3);
|
||||
|
||||
unsigned char *data = new unsigned char[rowPadded];
|
||||
unsigned char tmp;
|
||||
|
||||
u32 x = 0;
|
||||
for (u32 i = 0; i < height; i++)
|
||||
{
|
||||
fread(data, sizeof(unsigned char), rowPadded, file);
|
||||
for (u32 j = 0; j < width * 3; j += 3)
|
||||
{
|
||||
// Convert (B, G, R) to (R, G, B)
|
||||
tmp = data[j];
|
||||
data[j] = data[j + 2];
|
||||
data[j + 2] = tmp;
|
||||
|
||||
o_texture.data[x] = data[j];
|
||||
o_texture.data[x + 1] = data[j + 1];
|
||||
o_texture.data[x + 2] = data[j + 2];
|
||||
x += 3;
|
||||
}
|
||||
}
|
||||
delete[] t_path;
|
||||
delete[] data;
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTICE: Based on
|
||||
* https://github.com/mrqo/rw_parse/blob/master/rw_utils/rw_utils.cpp
|
||||
* rw_utils.cpp Written by Marek Iwaniuk (c).
|
||||
* Dff structure documentation http://www.chronetal.co.uk/gta/index.php?page=dff
|
||||
* Created on 02/04/2017 (MM/DD/YYYY)
|
||||
*/
|
||||
|
||||
#include "../include/loaders/dff_loader.hpp"
|
||||
#include "../include/utils/debug.hpp"
|
||||
#include "../include/utils/math.hpp"
|
||||
#include "../include/utils/string.hpp"
|
||||
#include <cstring>
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
DffLoader::DffLoader() {}
|
||||
|
||||
DffLoader::~DffLoader() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
void DffLoader::load(RwClump &o_clump, char *t_filename, float t_scale)
|
||||
{
|
||||
PRINT_LOG("Loading dff file");
|
||||
FILE *file = fopen(t_filename, "rb");
|
||||
if (file == NULL)
|
||||
PRINT_ERR("Failed to load .obj file!");
|
||||
fseek(file, 0L, SEEK_END);
|
||||
long fileSize = ftell(file);
|
||||
u8 *data = new u8[fileSize];
|
||||
rewind(file);
|
||||
fread(data, sizeof(u8), fileSize, file);
|
||||
fclose(file);
|
||||
serialize(o_clump, data, t_scale);
|
||||
delete[] data;
|
||||
PRINT_LOG("Dff file loaded!");
|
||||
}
|
||||
|
||||
void DffLoader::serialize(RwClump &t_clump, u8 *t_data, float t_scale)
|
||||
{
|
||||
u32 ptrPos = 0;
|
||||
readSectionHeader(t_clump, t_data, ptrPos);
|
||||
readSectionHeader(t_clump.data, t_data, ptrPos);
|
||||
readClumpData(t_clump.data, t_data, ptrPos);
|
||||
readSectionHeader(t_clump.frameList, t_data, ptrPos);
|
||||
readSectionHeader(t_clump.frameList.data, t_data, ptrPos);
|
||||
readFrameListData(t_clump.frameList.data, t_data, ptrPos);
|
||||
|
||||
t_clump.frameList.extensions = new RwFrameListExtension[t_clump.frameList.data.frameCount];
|
||||
for (u32 i = 0; i < t_clump.frameList.data.frameCount; i++)
|
||||
{
|
||||
readSectionHeader(t_clump.frameList.extensions[i], t_data, ptrPos);
|
||||
ptrPos += t_clump.frameList.extensions[i].sectionSize;
|
||||
}
|
||||
|
||||
readSectionHeader(t_clump.geometryList, t_data, ptrPos);
|
||||
readSectionHeader(t_clump.geometryList.data, t_data, ptrPos);
|
||||
readGeometryListData(t_clump.geometryList.data, t_data, ptrPos);
|
||||
|
||||
t_clump.geometryList.geometries = new RwGeometry[t_clump.geometryList.data.geometryCount];
|
||||
printf("Geometries:%d\n", t_clump.geometryList.data.geometryCount);
|
||||
for (u32 i = 0; i < t_clump.geometryList.data.geometryCount; i++)
|
||||
{
|
||||
readSectionHeader(t_clump.geometryList.geometries[i], t_data, ptrPos);
|
||||
readSectionHeader(t_clump.geometryList.geometries[i].data, t_data, ptrPos);
|
||||
readGeometryData(t_clump.geometryList.geometries[i].data, t_data, ptrPos, t_scale);
|
||||
|
||||
readSectionHeader(t_clump.geometryList.geometries[i].materialList, t_data, ptrPos);
|
||||
readSectionHeader(t_clump.geometryList.geometries[i].materialList.data, t_data, ptrPos);
|
||||
readMaterialListData(t_clump.geometryList.geometries[i].materialList.data, t_data, ptrPos);
|
||||
|
||||
u32 materialCount = t_clump.geometryList.geometries[i].materialList.data.materialCount;
|
||||
printf("Materials:%d\n", materialCount);
|
||||
|
||||
t_clump.geometryList.geometries[i].materialList.materials = new RwMaterial[materialCount];
|
||||
for (u32 j = 0; j < materialCount; j++)
|
||||
{
|
||||
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j], t_data, ptrPos);
|
||||
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].data, t_data, ptrPos);
|
||||
readMaterialData(t_clump.geometryList.geometries[i].materialList.materials[j].data, t_data, ptrPos);
|
||||
|
||||
u32 textureCount = t_clump.geometryList.geometries[i].materialList.materials[j].data.textureCount;
|
||||
t_clump.geometryList.geometries[i].materialList.materials[j].textures = new RwTexture[textureCount];
|
||||
for (u32 k = 0; k < textureCount; k++)
|
||||
{
|
||||
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k], t_data, ptrPos);
|
||||
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].data, t_data, ptrPos);
|
||||
readTextureData(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].data, t_data, ptrPos);
|
||||
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].textureName, t_data, ptrPos);
|
||||
readStringData(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].textureName, t_data, ptrPos);
|
||||
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].textureAlphaName, t_data, ptrPos);
|
||||
readStringData(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].textureAlphaName, t_data, ptrPos);
|
||||
|
||||
// The content of extension is Sky Mipmap Val
|
||||
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].extension, t_data, ptrPos);
|
||||
ptrPos += t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].extension.sectionSize;
|
||||
}
|
||||
// Probably always void extension
|
||||
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].extension, t_data, ptrPos);
|
||||
ptrPos += t_clump.geometryList.geometries[i].materialList.materials[j].extension.sectionSize;
|
||||
}
|
||||
// For Bin Mesh aka Material split
|
||||
readSectionHeader(t_clump.geometryList.geometries[i].extension, t_data, ptrPos);
|
||||
readGeometryExtension(t_clump.geometryList.geometries[i].extension, t_data, ptrPos);
|
||||
ptrPos += t_clump.geometryList.geometries[i].extension.sectionSize;
|
||||
}
|
||||
|
||||
readSectionHeader(t_clump.atomic, t_data, ptrPos);
|
||||
readSectionHeader(t_clump.atomic.data, t_data, ptrPos);
|
||||
ptrPos += t_clump.atomic.data.sectionSize;
|
||||
}
|
||||
|
||||
void DffLoader::readSectionHeader(RwSectionHeader &t_sh, u8 *t_buffer, u32 &t_ptrPos)
|
||||
{
|
||||
t_sh.sectionType = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_sh.sectionSize = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_sh.versionNumber = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
void DffLoader::readFrameListData(RwFrameListData &t_frd, u8 *t_buffer, u32 &t_ptrPos)
|
||||
{
|
||||
t_frd.frameCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
printf("Frame count:%d\n", t_frd.frameCount);
|
||||
t_frd.frameInformation = new RwFrameListChunk[t_frd.frameCount];
|
||||
|
||||
for (u32 i = 0; i < t_frd.frameCount; i++)
|
||||
{
|
||||
t_frd.frameInformation[i].rotationalMatrix = new float[t_frd.ROT_MAT_DIM];
|
||||
for (u32 j = 0; j < t_frd.ROT_MAT_DIM; j++)
|
||||
t_frd.frameInformation[i].rotationalMatrix[j] = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
|
||||
t_frd.frameInformation[i].coordinatesOffsetX = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_frd.frameInformation[i].coordinatesOffsetY = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_frd.frameInformation[i].coordinatesOffsetZ = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_frd.frameInformation[i]
|
||||
.parentFrame = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_frd.frameInformation[i].unk1 = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
}
|
||||
}
|
||||
|
||||
void DffLoader::readClumpData(RwClumpData &t_cd, u8 *t_buffer, u32 &t_ptrPos)
|
||||
{
|
||||
t_cd.objectCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_cd.unk1 = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_cd.unk2 = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
}
|
||||
|
||||
void DffLoader::readGeometryListData(RwGeometryListData &t_gld, u8 *t_buffer, u32 &t_ptrPos)
|
||||
{
|
||||
t_gld.geometryCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
}
|
||||
|
||||
void DffLoader::readGeometryExtension(RwGeometryExtension &t_ge, u8 *t_buffer, u32 &t_ptrPos)
|
||||
{
|
||||
for (u8 i = 0; i < 3; i++)
|
||||
t_ptrPos += sizeof(u32);
|
||||
|
||||
t_ge.materialSplit.header.triangleStrip = readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_ge.materialSplit.header.splitCount = readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_ge.materialSplit.header.faceCount = readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
|
||||
t_ge.materialSplit.splitInformation = new RwGeometryListInfoChunk[t_ge.materialSplit.header.splitCount];
|
||||
for (u32 i = 0; i < t_ge.materialSplit.header.splitCount; i++)
|
||||
{
|
||||
t_ge.materialSplit.splitInformation[i].faceIndex = readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_ge.materialSplit.splitInformation[i].materialIndex = readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
|
||||
t_ge.materialSplit.splitInformation[i].vertexInformation = new RwGeometryListVertexInfoChunk[t_ge.materialSplit.splitInformation[i].faceIndex];
|
||||
for (u32 j = 0; j < t_ge.materialSplit.splitInformation[i].faceIndex; j++)
|
||||
t_ge.materialSplit.splitInformation[i].vertexInformation[j].vertex1 = readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
}
|
||||
}
|
||||
|
||||
void DffLoader::readGeometryData(RwGeometryData &t_gd, u8 *t_buffer, u32 &t_ptrPos, float t_scale)
|
||||
{
|
||||
t_gd.dataHeader.flags = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.dataHeader.unk1 = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.dataHeader.triangleCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.dataHeader.vertexCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.dataHeader.morphTargetCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
|
||||
if (false)
|
||||
{ // version equals 4099 according to old documentation, disabled as for now
|
||||
t_gd.lightingHeader.ambient = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.lightingHeader.diffuse = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.lightingHeader.specular = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
}
|
||||
|
||||
if (t_gd.dataHeader.flags & rwOBJECT_VERTEX_PRELIT)
|
||||
{
|
||||
t_gd.colorInformation = new RwGeometryDataColorInformationChunk[t_gd.dataHeader.vertexCount];
|
||||
for (u32 i = 0; i < t_gd.dataHeader.vertexCount; i++)
|
||||
{
|
||||
t_gd.colorInformation[i].red = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.colorInformation[i].green = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.colorInformation[i].blue = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.colorInformation[i].alpha = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||
}
|
||||
}
|
||||
|
||||
if (t_gd.dataHeader.flags & rwOBJECT_VERTEX_TEXTURED)
|
||||
{
|
||||
t_gd.textureMappingInformation = new RwGeometryDataTextureMappingInformationChunk[t_gd.dataHeader.vertexCount];
|
||||
for (u32 i = 0; i < t_gd.dataHeader.vertexCount; i++)
|
||||
{
|
||||
t_gd.textureMappingInformation[i].u = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.textureMappingInformation[i].v = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
}
|
||||
}
|
||||
|
||||
t_gd.faceInformation = new RwGeometryDataFaceInformation[t_gd.dataHeader.triangleCount];
|
||||
for (u32 i = 0; i < t_gd.dataHeader.triangleCount; i++)
|
||||
{
|
||||
t_gd.faceInformation[i].vertex2 = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.faceInformation[i].vertex1 = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.faceInformation[i].flags = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.faceInformation[i].vertex3 = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||
}
|
||||
|
||||
t_gd.nonameInfo.boundingSphereX = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.nonameInfo.boundingSphereY = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.nonameInfo.boundingSphereZ = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.nonameInfo.boundingSphereR = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.nonameInfo.hasPosition = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.nonameInfo.hasNormals = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
|
||||
t_gd.vertexInformation = new Vector3[t_gd.dataHeader.vertexCount];
|
||||
for (u32 i = 0; i < t_gd.dataHeader.vertexCount; i++)
|
||||
{
|
||||
t_gd.vertexInformation[i].x = readFloatFromArrayLE(t_buffer, t_ptrPos) * t_scale;
|
||||
t_gd.vertexInformation[i].y = readFloatFromArrayLE(t_buffer, t_ptrPos) * t_scale;
|
||||
t_gd.vertexInformation[i].z = readFloatFromArrayLE(t_buffer, t_ptrPos) * t_scale;
|
||||
}
|
||||
|
||||
if (t_gd.dataHeader.flags & rwOBJECT_VERTEX_NORMALS)
|
||||
{
|
||||
t_gd.normalInformation = new Vector3[t_gd.dataHeader.vertexCount];
|
||||
for (u32 i = 0; i < t_gd.dataHeader.vertexCount; i++)
|
||||
{
|
||||
t_gd.normalInformation[i].x = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.normalInformation[i].y = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_gd.normalInformation[i].z = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DffLoader::readMaterialListData(RwMaterialListData &t_mld, u8 *t_buffer, u32 &t_ptrPos)
|
||||
{
|
||||
t_mld.materialCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_mld.arrayOfUnks = new u32[t_mld.materialCount];
|
||||
for (u32 i = 0; i < t_mld.materialCount; i++)
|
||||
{
|
||||
t_mld.arrayOfUnks[i] = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
}
|
||||
}
|
||||
|
||||
void DffLoader::readMaterialData(RwMaterialData &t_md, u8 *t_buffer, u32 &t_ptrPos)
|
||||
{
|
||||
t_md.unk1 = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_md.R = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_md.G = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_md.B = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_md.A = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_md.unk2 = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_md.textureCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_md.unkPosX = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_md.unkPosY = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_md.unkPosZ = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||
}
|
||||
|
||||
void DffLoader::readTextureData(RwTextureData &t_td, u8 *t_buffer, u32 &t_ptrPos)
|
||||
{
|
||||
t_td.textureFilterModeFlags = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||
t_td.unk = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||
}
|
||||
|
||||
void DffLoader::readStringData(RwString &t_s, u8 *t_buffer, u32 &t_ptrPos)
|
||||
{
|
||||
t_s.text = readString(t_buffer, t_ptrPos, t_s.sectionSize);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
u8 DffLoader::readByteFromArrayLE(u8 *t_buffer, u32 &t_ptrPos)
|
||||
{
|
||||
return t_buffer[t_ptrPos++];
|
||||
}
|
||||
|
||||
u16 DffLoader::readWordFromArrayLE(u8 *t_buffer, u32 &t_ptrPos)
|
||||
{
|
||||
u16 res = (t_buffer[t_ptrPos + 1] << 8) + (t_buffer[t_ptrPos]);
|
||||
t_ptrPos += sizeof(u16);
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 DffLoader::readDwordFromArrayLE(u8 *t_buffer, u32 &t_ptrPos)
|
||||
{
|
||||
u32 res = (t_buffer[t_ptrPos + 3] << 24) + (t_buffer[t_ptrPos + 2] << 16) + (t_buffer[t_ptrPos + 1] << 8) + (t_buffer[t_ptrPos]);
|
||||
t_ptrPos += sizeof(u32);
|
||||
return res;
|
||||
}
|
||||
|
||||
float DffLoader::readFloatFromArrayLE(u8 *t_buffer, u32 &t_ptrPos)
|
||||
{
|
||||
float res;
|
||||
memcpy(&res, t_buffer + t_ptrPos, sizeof(float));
|
||||
t_ptrPos += sizeof(float);
|
||||
return res;
|
||||
}
|
||||
|
||||
u8 *DffLoader::readData(u8 *t_buffer, u32 &t_ptrPos, u32 t_dataSize)
|
||||
{
|
||||
u8 *arr = new u8[t_dataSize];
|
||||
for (u32 i = 0; i < t_dataSize; ++i)
|
||||
arr[i] = t_buffer[i + t_ptrPos];
|
||||
t_ptrPos += t_dataSize;
|
||||
return arr;
|
||||
}
|
||||
|
||||
char *DffLoader::readString(u8 *t_buffer, u32 &t_ptrPos, u32 t_dataSize)
|
||||
{
|
||||
u32 strLength = String::getLength((char *)&t_buffer[t_ptrPos]);
|
||||
char *result = new char[strLength + 1];
|
||||
for (u32 i = 0; i < strLength; i++)
|
||||
result[i] = (char)t_buffer[t_ptrPos + i];
|
||||
result[strLength] = '\0';
|
||||
t_ptrPos += t_dataSize;
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/loaders/md2_loader.hpp"
|
||||
|
||||
#include "../include/utils/debug.hpp"
|
||||
#include "../include/models/math/vector3.hpp"
|
||||
#include "../include/models/math/point.hpp"
|
||||
#include <string.h>
|
||||
#include <iosfwd>
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
MD2Loader::MD2Loader() {}
|
||||
|
||||
MD2Loader::~MD2Loader() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
/** Load, parse .obj file and load data into given MeshSpec */
|
||||
void MD2Loader::load(MD2Model *o_result, char *t_filename, float t_scale)
|
||||
{
|
||||
PRINT_LOG("Loading new MD2 file");
|
||||
md2_t header; // md2 header
|
||||
char *buffer; // buffer storing frame data
|
||||
|
||||
FILE *file = fopen(t_filename, "rb");
|
||||
|
||||
if (file == NULL)
|
||||
PRINT_ERR("Failed to load .md2 file!");
|
||||
|
||||
fread((char *)&header, sizeof(md2_t), 1, file);
|
||||
|
||||
if ((header.ident != MD2_IDENT) && (header.version != MD2_VERSION))
|
||||
PRINT_ERR("This MD2 file was not in correct format!");
|
||||
|
||||
o_result->framesCount = header.num_frames;
|
||||
o_result->verticesPerFrameCount = header.num_xyz;
|
||||
o_result->coordinatesCount = header.num_st;
|
||||
o_result->trianglesCount = header.num_tris;
|
||||
|
||||
printf("MD2 - Frames: %d\n", header.num_frames);
|
||||
printf("MD2 - Vert: %d\n", header.num_xyz);
|
||||
printf("MD2 - Tris: %d\n", header.num_tris);
|
||||
printf("MD2 - STs: %d\n", header.num_st);
|
||||
printf("MD2 - Skin W:%d H: %d\n", header.skinwidth, header.skinheight);
|
||||
|
||||
o_result->allocateMemory();
|
||||
|
||||
buffer = new char[o_result->framesCount * header.framesize];
|
||||
fseek(file, header.ofs_frames, SEEK_SET);
|
||||
fread((char *)buffer, o_result->framesCount * header.framesize, 1, file);
|
||||
|
||||
frame_t *frame; // temporary vars
|
||||
Vector3 *ptrVerts;
|
||||
u32 *ptrNormals;
|
||||
// vertex array initialization
|
||||
for (u32 j = 0; j < o_result->framesCount; j++)
|
||||
{
|
||||
frame = (frame_t *)&buffer[header.framesize * j];
|
||||
ptrVerts = &o_result->vertices[o_result->verticesPerFrameCount * j];
|
||||
ptrNormals = &o_result->normalIndexes[o_result->verticesPerFrameCount * j];
|
||||
|
||||
for (u32 i = 0; i < o_result->verticesPerFrameCount; i++)
|
||||
{
|
||||
ptrVerts[i].x = ((frame->verts[i].v[0] * frame->scale[0]) + frame->translate[0]) * t_scale;
|
||||
ptrVerts[i].y = ((frame->verts[i].v[1] * frame->scale[1]) + frame->translate[1]) * t_scale;
|
||||
ptrVerts[i].z = ((frame->verts[i].v[2] * frame->scale[2]) + frame->translate[2]) * t_scale;
|
||||
|
||||
ptrNormals[i] = frame->verts[i].lightnormalindex;
|
||||
}
|
||||
if (j == o_result->framesCount - 1)
|
||||
printf("Last frame, last vert: X:%f Y:%f Z:%f\n",
|
||||
ptrVerts[o_result->verticesPerFrameCount - 1].x,
|
||||
ptrVerts[o_result->verticesPerFrameCount - 1].y,
|
||||
ptrVerts[o_result->verticesPerFrameCount - 1].z);
|
||||
}
|
||||
delete[] buffer;
|
||||
|
||||
buffer = new char[o_result->coordinatesCount * sizeof(texCoord_t)];
|
||||
fseek(file, header.ofs_st, SEEK_SET);
|
||||
fread((char *)buffer, o_result->coordinatesCount * sizeof(texCoord_t), 1, file);
|
||||
|
||||
texCoord_t *texCoord;
|
||||
for (u32 i = 0; i < o_result->coordinatesCount; i++)
|
||||
{
|
||||
texCoord = (texCoord_t *)&buffer[sizeof(texCoord_t) * i];
|
||||
o_result->coordinates[i].x = (float)texCoord->s / header.skinwidth;
|
||||
o_result->coordinates[i].y = (float)texCoord->t / header.skinheight;
|
||||
}
|
||||
delete[] buffer;
|
||||
|
||||
printf("Last tex coord(%d): S:%f T:%f\n",
|
||||
o_result->coordinatesCount,
|
||||
o_result->coordinates[o_result->coordinatesCount - 1].x,
|
||||
o_result->coordinates[o_result->coordinatesCount - 1].y);
|
||||
|
||||
buffer = new char[o_result->trianglesCount * sizeof(triangle_t)];
|
||||
fseek(file, header.ofs_tris, SEEK_SET);
|
||||
fread((char *)buffer, o_result->trianglesCount * sizeof(triangle_t), 1, file);
|
||||
|
||||
triangle_t *triangle; // temporary var
|
||||
// vertex array initialization
|
||||
for (u32 i = 0; i < o_result->trianglesCount; i++)
|
||||
{
|
||||
triangle = (triangle_t *)&buffer[sizeof(triangle_t) * i];
|
||||
for (u8 j = 0; j < 3; j++)
|
||||
{
|
||||
o_result->triangles[i].verticeIndexes[j] = triangle->index_xyz[j];
|
||||
o_result->triangles[i].coordIndexes[j] = triangle->index_st[j];
|
||||
}
|
||||
}
|
||||
delete[] buffer;
|
||||
|
||||
fclose(file);
|
||||
PRINT_LOG("MD2 file loaded!");
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/loaders/obj_loader.hpp"
|
||||
|
||||
#include "../include/utils/debug.hpp"
|
||||
#include <string.h>
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
ObjLoader::ObjLoader() {}
|
||||
|
||||
ObjLoader::~ObjLoader() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
/** Load, parse .obj file and load data into given MeshSpec */
|
||||
void ObjLoader::load(ObjModel *o_result, char *t_filename, float t_scale)
|
||||
{
|
||||
FILE *file = fopen(t_filename, "rb");
|
||||
if (file == NULL)
|
||||
PRINT_ERR("Failed to load .obj file!");
|
||||
setObjDataQuantities(file, o_result);
|
||||
o_result->allocateMemory();
|
||||
u32 verticesI = 0, cordsI = 0, normalsI = 0, i = 0, vertexIndex[3], coordIndex[3], normalIndex[3];
|
||||
while (1)
|
||||
{
|
||||
char lineHeader[128]; // read the first word of the line
|
||||
int res = fscanf(file, "%s", lineHeader);
|
||||
if (res != EOF)
|
||||
{
|
||||
if (strcmp(lineHeader, "v") == 0)
|
||||
{
|
||||
Vector3 vector = Vector3();
|
||||
fscanf(file, "%f %f %f\n", &vector.x, &vector.y, &vector.z);
|
||||
o_result->vertices[verticesI++] = vector * t_scale;
|
||||
}
|
||||
else if (strcmp(lineHeader, "vt") == 0)
|
||||
{
|
||||
Vector3 vector = Vector3();
|
||||
fscanf(file, "%f %f\n", &vector.x, &vector.y);
|
||||
o_result->coordinates[cordsI++] = vector;
|
||||
}
|
||||
else if (strcmp(lineHeader, "vn") == 0)
|
||||
{
|
||||
Vector3 vector = Vector3();
|
||||
fscanf(file, "%f %f %f\n", &vector.x, &vector.y, &vector.z);
|
||||
o_result->normals[normalsI++] = vector;
|
||||
}
|
||||
else if (strcmp(lineHeader, "f") == 0)
|
||||
{
|
||||
int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n",
|
||||
&vertexIndex[0], &coordIndex[0], &normalIndex[0],
|
||||
&vertexIndex[1], &coordIndex[1], &normalIndex[1],
|
||||
&vertexIndex[2], &coordIndex[2], &normalIndex[2]);
|
||||
if (matches != 9)
|
||||
PRINT_ERR(".obj can't be read by this simple parser. Try exporting with other options");
|
||||
else
|
||||
{
|
||||
o_result->verticeFaces[i] = vertexIndex[0] - 1;
|
||||
o_result->verticeFaces[i + 1] = vertexIndex[1] - 1;
|
||||
o_result->verticeFaces[i + 2] = vertexIndex[2] - 1;
|
||||
|
||||
o_result->coordinateFaces[i] = coordIndex[0] - 1;
|
||||
o_result->coordinateFaces[i + 1] = coordIndex[1] - 1;
|
||||
o_result->coordinateFaces[i + 2] = coordIndex[2] - 1;
|
||||
|
||||
o_result->normalFaces[i] = normalIndex[0] - 1;
|
||||
o_result->normalFaces[i + 1] = normalIndex[1] - 1;
|
||||
o_result->normalFaces[i + 2] = normalIndex[2] - 1;
|
||||
i += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/** Calculate how many vertices(v), coordinates(vt), normals(vn) and faces(f) have .obj file
|
||||
* When done, file read offset is resetted to the begginning of file
|
||||
*/
|
||||
void ObjLoader::setObjDataQuantities(FILE *t_file, ObjModel *o_result)
|
||||
{
|
||||
o_result->verticesCount = 0;
|
||||
o_result->coordinatesCount = 0;
|
||||
o_result->normalsCount = 0;
|
||||
o_result->facesCount = 0;
|
||||
while (1)
|
||||
{
|
||||
char lineHeader[128];
|
||||
int res = fscanf(t_file, "%s", lineHeader);
|
||||
if (res != EOF)
|
||||
{
|
||||
if (strcmp(lineHeader, "v") == 0)
|
||||
o_result->verticesCount += 1;
|
||||
else if (strcmp(lineHeader, "vt") == 0)
|
||||
o_result->coordinatesCount += 1;
|
||||
else if (strcmp(lineHeader, "vn") == 0)
|
||||
o_result->normalsCount += 1;
|
||||
else if (strcmp(lineHeader, "f") == 0)
|
||||
o_result->facesCount += 3;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
fseek(t_file, 0, SEEK_SET);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/models/dff_model.hpp"
|
||||
|
||||
#include "../include/utils/debug.hpp"
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
DffModel::DffModel() {}
|
||||
|
||||
DffModel::~DffModel() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
u32 DffModel::getDrawData(u32 splitIndex, VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, Vector3 &t_cameraPos, float t_scale, u8 t_shouldBeBackfaceCulled)
|
||||
{
|
||||
u32 result = 0;
|
||||
for (u32 i = 0; i < clump.geometryList.geometries[0].extension.materialSplit.splitInformation[splitIndex].faceIndex; i++)
|
||||
fillNextFace(o_vertices, o_normals, o_coordinates, o_colors, 0,
|
||||
clump.geometryList.geometries[0].extension.materialSplit.splitInformation[splitIndex].vertexInformation[i].vertex1,
|
||||
result++);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DffModel::fillNextFace(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, u8 geometry, u32 t_getI, u32 t_setI)
|
||||
{
|
||||
o_vertices[t_setI][0] = clump.geometryList.geometries[geometry].data.vertexInformation[t_getI].x;
|
||||
o_vertices[t_setI][1] = clump.geometryList.geometries[geometry].data.vertexInformation[t_getI].y;
|
||||
o_vertices[t_setI][2] = clump.geometryList.geometries[geometry].data.vertexInformation[t_getI].z;
|
||||
o_vertices[t_setI][3] = 1.0F;
|
||||
|
||||
o_normals[t_setI][0] = clump.geometryList.geometries[geometry].data.normalInformation[t_getI].x;
|
||||
o_normals[t_setI][1] = clump.geometryList.geometries[geometry].data.normalInformation[t_getI].y;
|
||||
o_normals[t_setI][2] = clump.geometryList.geometries[geometry].data.normalInformation[t_getI].z;
|
||||
o_normals[t_setI][3] = 1.0F;
|
||||
|
||||
o_coordinates[t_setI][0] = clump.geometryList.geometries[geometry].data.textureMappingInformation[t_getI].u;
|
||||
o_coordinates[t_setI][1] = 1.0F - clump.geometryList.geometries[geometry].data.textureMappingInformation[t_getI].v;
|
||||
o_coordinates[t_setI][2] = 1.0F;
|
||||
o_coordinates[t_setI][3] = 1.0F;
|
||||
|
||||
o_colors[t_setI][0] = 1.0F;
|
||||
o_colors[t_setI][1] = 1.0F;
|
||||
o_colors[t_setI][2] = 1.0F;
|
||||
o_colors[t_setI][3] = 1.0F;
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../../include/models/math/matrix.hpp"
|
||||
|
||||
#include "../../include/utils/math.hpp"
|
||||
#include <stdio.h>
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
/** Create by specifying all points */
|
||||
Matrix::Matrix(float m11, float m12, float m13, float m14,
|
||||
float m21, float m22, float m23, float m24,
|
||||
float m31, float m32, float m33, float m34,
|
||||
float m41, float m42, float m43, float m44)
|
||||
{
|
||||
data[0] = m11;
|
||||
data[1] = m12;
|
||||
data[2] = m13;
|
||||
data[3] = m14;
|
||||
|
||||
data[4] = m21;
|
||||
data[5] = m22;
|
||||
data[6] = m23;
|
||||
data[7] = m24;
|
||||
|
||||
data[8] = m31;
|
||||
data[9] = m32;
|
||||
data[10] = m33;
|
||||
data[11] = m34;
|
||||
|
||||
data[12] = m41;
|
||||
data[13] = m42;
|
||||
data[14] = m43;
|
||||
data[15] = m44;
|
||||
}
|
||||
|
||||
/** Create with another matrix values */
|
||||
Matrix::Matrix(const Matrix &v)
|
||||
{
|
||||
data[0] = v.data[0];
|
||||
data[1] = v.data[1];
|
||||
data[2] = v.data[2];
|
||||
data[3] = v.data[3];
|
||||
|
||||
data[4] = v.data[4];
|
||||
data[5] = v.data[5];
|
||||
data[6] = v.data[6];
|
||||
data[7] = v.data[7];
|
||||
|
||||
data[8] = v.data[8];
|
||||
data[9] = v.data[9];
|
||||
data[10] = v.data[10];
|
||||
data[11] = v.data[11];
|
||||
|
||||
data[12] = v.data[12];
|
||||
data[13] = v.data[13];
|
||||
data[14] = v.data[14];
|
||||
data[15] = v.data[15];
|
||||
}
|
||||
|
||||
void Matrix::identity()
|
||||
{
|
||||
asm volatile(
|
||||
"vsub.xyzw vf4, vf0, vf0 \n\t"
|
||||
"vadd.w vf4, vf4, vf0 \n\t"
|
||||
"vmr32.xyzw vf5, vf4 \n\t"
|
||||
"vmr32.xyzw vf6, vf5 \n\t"
|
||||
"vmr32.xyzw vf7, vf6 \n\t"
|
||||
"sqc2 vf4, 0x30(%0) \n\t"
|
||||
"sqc2 vf5, 0x20(%0) \n\t"
|
||||
"sqc2 vf6, 0x10(%0) \n\t"
|
||||
"sqc2 vf7, 0x0(%0) \n\t"
|
||||
:
|
||||
: "r"(this->data));
|
||||
}
|
||||
|
||||
void Matrix::translate(float x, float y, float z)
|
||||
{
|
||||
this->identity();
|
||||
this->data[(3 << 2) + 0] = x; // 3,0
|
||||
this->data[(3 << 2) + 1] = y; // 3,1
|
||||
this->data[(3 << 2) + 2] = z; // 3,2
|
||||
}
|
||||
|
||||
void Matrix::makeZRotation(float t_radians)
|
||||
{
|
||||
this->identity();
|
||||
float c = Math::cos(t_radians);
|
||||
float s = Math::sin(t_radians);
|
||||
this->data[0] = c; // 0,0
|
||||
this->data[1] = s; // 0,1
|
||||
this->data[4] = -s; // 1,0
|
||||
this->data[5] = c; // 1,1
|
||||
}
|
||||
|
||||
Matrix Matrix::operator*(Matrix &t)
|
||||
{
|
||||
Matrix result;
|
||||
asm volatile(
|
||||
"lqc2 vf1, 0x00(%1) \n\t"
|
||||
"lqc2 vf2, 0x10(%1) \n\t"
|
||||
"lqc2 vf3, 0x20(%1) \n\t"
|
||||
"lqc2 vf4, 0x30(%1) \n\t"
|
||||
"lqc2 vf5, 0x00(%2) \n\t"
|
||||
"lqc2 vf6, 0x10(%2) \n\t"
|
||||
"lqc2 vf7, 0x20(%2) \n\t"
|
||||
"lqc2 vf8, 0x30(%2) \n\t"
|
||||
"vmulax.xyzw ACC, vf5, vf1 \n\t"
|
||||
"vmadday.xyzw ACC, vf6, vf1 \n\t"
|
||||
"vmaddaz.xyzw ACC, vf7, vf1 \n\t"
|
||||
"vmaddw.xyzw vf1, vf8, vf1 \n\t"
|
||||
"vmulax.xyzw ACC, vf5, vf2 \n\t"
|
||||
"vmadday.xyzw ACC, vf6, vf2 \n\t"
|
||||
"vmaddaz.xyzw ACC, vf7, vf2 \n\t"
|
||||
"vmaddw.xyzw vf2, vf8, vf2 \n\t"
|
||||
"vmulax.xyzw ACC, vf5, vf3 \n\t"
|
||||
"vmadday.xyzw ACC, vf6, vf3 \n\t"
|
||||
"vmaddaz.xyzw ACC, vf7, vf3 \n\t"
|
||||
"vmaddw.xyzw vf3, vf8, vf3 \n\t"
|
||||
"vmulax.xyzw ACC, vf5, vf4 \n\t"
|
||||
"vmadday.xyzw ACC, vf6, vf4 \n\t"
|
||||
"vmaddaz.xyzw ACC, vf7, vf4 \n\t"
|
||||
"vmaddw.xyzw vf4, vf8, vf4 \n\t"
|
||||
"sqc2 vf1, 0x00(%0) \n\t"
|
||||
"sqc2 vf2, 0x10(%0) \n\t"
|
||||
"sqc2 vf3, 0x20(%0) \n\t"
|
||||
"sqc2 vf4, 0x30(%0) \n\t"
|
||||
:
|
||||
: "r"(result.data), "r"(this->data), "r"(t.data)
|
||||
: "memory");
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Create empty matrix */
|
||||
Matrix::Matrix()
|
||||
{
|
||||
data[0] = 0.0F;
|
||||
data[1] = 0.0F;
|
||||
data[2] = 0.0F;
|
||||
data[3] = 0.0F;
|
||||
|
||||
data[4] = 0.0F;
|
||||
data[5] = 0.0F;
|
||||
data[6] = 0.0F;
|
||||
data[7] = 0.0F;
|
||||
|
||||
data[8] = 0.0F;
|
||||
data[9] = 0.0F;
|
||||
data[10] = 0.0F;
|
||||
data[11] = 0.0F;
|
||||
|
||||
data[12] = 0.0F;
|
||||
data[13] = 0.0F;
|
||||
data[14] = 0.0F;
|
||||
data[15] = 0.0F;
|
||||
}
|
||||
|
||||
Matrix::~Matrix() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
/** Set up a perspective projection matrix
|
||||
*
|
||||
* Clone of gluPerspective()
|
||||
* https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml
|
||||
* @param fov (FOV in radians)/2
|
||||
* @param aspect Aspect ratio
|
||||
* @param scrW Half of screen width
|
||||
* @param scrH Half of screen height
|
||||
* @param zNear Distance to near plane
|
||||
* @param zFar Distance to far plane
|
||||
* @param projScale Projection scale
|
||||
*/
|
||||
void Matrix::setPerspective(ScreenSettings &t_screen)
|
||||
{
|
||||
float fovYdiv2 = Math::HALF_ANG2RAD * t_screen.fov;
|
||||
float cotFOV = 1.0F / (Math::sin(fovYdiv2) / Math::cos(fovYdiv2));
|
||||
float w = cotFOV * (t_screen.width / 4096.0F) / t_screen.aspectRatio;
|
||||
float h = cotFOV * (t_screen.height / 4096.0F);
|
||||
|
||||
this->data[0] = w;
|
||||
this->data[1] = 0.0F;
|
||||
this->data[2] = 0.0F;
|
||||
this->data[3] = 0.0F;
|
||||
|
||||
this->data[4] = 0.0F;
|
||||
this->data[5] = -h;
|
||||
this->data[6] = 0.0F;
|
||||
this->data[7] = 0.0F;
|
||||
|
||||
this->data[8] = 0.0F;
|
||||
this->data[9] = 0.0F;
|
||||
this->data[10] =
|
||||
(t_screen.farPlaneDist + t_screen.nearPlaneDist) /
|
||||
(t_screen.farPlaneDist - t_screen.nearPlaneDist);
|
||||
this->data[11] = -1.0F;
|
||||
|
||||
this->data[12] = 0.0F;
|
||||
this->data[13] = 0.0F;
|
||||
this->data[14] =
|
||||
(2.0F * t_screen.farPlaneDist * t_screen.nearPlaneDist) /
|
||||
(t_screen.farPlaneDist - t_screen.nearPlaneDist);
|
||||
this->data[15] = 0.0F;
|
||||
}
|
||||
|
||||
/** Create a view matrix that transforms coordinates in
|
||||
* such a way that the user looks at a target vector
|
||||
* direction from a position vector.
|
||||
*
|
||||
* Clone of OpenGL lookAt function
|
||||
* https://learnopengl.com/Getting-started/Camera
|
||||
*/
|
||||
void Matrix::lookAt(Vector3 &t_up, Vector3 &t_position, Vector3 &t_target)
|
||||
{
|
||||
Vector3 camForward, camUp, camRight;
|
||||
|
||||
camForward = t_position - t_target;
|
||||
camForward.normalize();
|
||||
camRight = t_up * camForward;
|
||||
camRight.normalize();
|
||||
camUp = camForward * camRight;
|
||||
|
||||
data[0] = camRight.x;
|
||||
data[4] = camRight.y;
|
||||
data[8] = camRight.z;
|
||||
data[12] = -camRight.innerProduct(t_position);
|
||||
|
||||
data[1] = camUp.x;
|
||||
data[5] = camUp.y;
|
||||
data[9] = camUp.z;
|
||||
data[13] = -camUp.innerProduct(t_position);
|
||||
|
||||
data[2] = camForward.x;
|
||||
data[6] = camForward.y;
|
||||
data[10] = camForward.z;
|
||||
data[14] = -camForward.innerProduct(t_position);
|
||||
|
||||
data[3] = 0;
|
||||
data[7] = 0;
|
||||
data[11] = 0;
|
||||
data[15] = 1;
|
||||
}
|
||||
|
||||
void Matrix::print()
|
||||
{
|
||||
printf("MATRIX(\n%f, %f, %f, %f\n%f, %f, %f, %f\n%f, %f, %f, %f\n%f, %f, %f, %f\n)\n",
|
||||
data[0], data[1], data[2], data[3],
|
||||
data[4], data[5], data[6], data[7],
|
||||
data[8], data[9], data[10], data[11],
|
||||
data[12], data[13], data[14], data[15]);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../../include/models/math/plane.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
/** Create empty plane */
|
||||
Plane::Plane() { this->distance = 0; }
|
||||
|
||||
/** Create by specyfying 3 points.
|
||||
* This function assumes that the points
|
||||
* are given in counter clockwise order
|
||||
*/
|
||||
Plane::Plane(Vector3 &a, Vector3 &b, Vector3 &c) { this->update(a, b, c); }
|
||||
|
||||
Plane::~Plane() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
/** Set plane by specyfying 3 points.
|
||||
* This function assumes that the points
|
||||
* are given in counter clockwise order
|
||||
*/
|
||||
void Plane::update(Vector3 &a, Vector3 &b, Vector3 &c)
|
||||
{
|
||||
Vector3 aux1 = a - b;
|
||||
Vector3 aux2 = c - b;
|
||||
this->normal = aux2 * aux1;
|
||||
this->normal.normalize();
|
||||
this->distance = -this->normal.innerProduct(b);
|
||||
}
|
||||
|
||||
void Plane::print()
|
||||
{
|
||||
printf("Plane(Vector3(%f, %f, %f), %f)\n", this->normal.x, this->normal.y, this->normal.z, this->distance);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../../include/models/math/point.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
/** Create by specifying values */
|
||||
Point::Point(float x, float y)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
||||
|
||||
/** Create empty point */
|
||||
Point::Point()
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
Point::~Point() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
void Point::set(float x, float y)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
||||
|
||||
void Point::print()
|
||||
{
|
||||
printf("Point(%f, %f)\n", x, y);
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../../include/models/math/vector3.hpp"
|
||||
|
||||
#include "../../include/utils/math.hpp"
|
||||
#include <stdio.h>
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
/** Create by specifying 3 points */
|
||||
Vector3::Vector3(float x, float y, float z)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->z = z;
|
||||
}
|
||||
|
||||
/** Create with another vector values */
|
||||
Vector3::Vector3(const Vector3 &another)
|
||||
{
|
||||
x = another.x;
|
||||
y = another.y;
|
||||
z = another.z;
|
||||
}
|
||||
|
||||
void Vector3::setByLerp(const Vector3 &v1, const Vector3 &v2, const float t_interp)
|
||||
{
|
||||
asm volatile(
|
||||
"lqc2 vf4, 0x0(%1) \n\t" // vf4 = v1
|
||||
"lqc2 vf5, 0x0(%2) \n\t" // vf5 = v2
|
||||
"mfc1 $8, %3 \n\t" // vf6 = t
|
||||
"qmtc2 $8, vf6 \n\t" // lerp:
|
||||
"vsub.xyz vf7, vf5, vf4 \n\t" // vf7 = v2 - v1
|
||||
"vmulx.xyz vf8, vf7, vf6 \n\t" // vf8 = vf7 * t
|
||||
"vadd.xyz vf9, vf8, vf4 \n\t" // vf9 = vf8 + vf4
|
||||
"sqc2 vf9, 0x0(%0) \n\t" // v0 = vf9
|
||||
:
|
||||
: "r"(&this->xyz), "r"(&v1.xyz), "r"(&v2.xyz), "f"(t_interp)
|
||||
: "$8");
|
||||
}
|
||||
|
||||
/** Create empty vector */
|
||||
Vector3::Vector3()
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
}
|
||||
|
||||
Vector3::~Vector3() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
Vector3 Vector3::operator+(Vector3 v)
|
||||
{
|
||||
Vector3 result;
|
||||
asm volatile( // VU0 Macro program
|
||||
"lqc2 vf4, 0x0(%1) \n\t"
|
||||
"lqc2 vf5, 0x0(%2) \n\t"
|
||||
"vadd.xyz vf6, vf4, vf5 \n\t"
|
||||
"sqc2 vf6, 0x0(%0) \n\t"
|
||||
:
|
||||
: "r"(result.xyz), "r"(this->xyz), "r"(v.xyz));
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector3 Vector3::operator-(const Vector3 &v)
|
||||
{
|
||||
Vector3 result;
|
||||
asm volatile( // VU0 Macro program
|
||||
"lqc2 vf4, 0x0(%1) \n\t"
|
||||
"lqc2 vf5, 0x0(%2) \n\t"
|
||||
"vsub.xyz vf6, vf4, vf5 \n\t"
|
||||
"sqc2 vf6, 0x0(%0) \n\t"
|
||||
:
|
||||
: "r"(result.xyz), "r"(this->xyz), "r"(v.xyz));
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector3 Vector3::operator-(void)
|
||||
{
|
||||
Vector3 result;
|
||||
result.x = -x;
|
||||
result.y = -y;
|
||||
result.z = -z;
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Also called "cross product" */
|
||||
Vector3 Vector3::operator*(Vector3 &v)
|
||||
{
|
||||
Vector3 res;
|
||||
asm volatile( // VU0 Macro program
|
||||
"lqc2 vf4, 0x0(%1) \n\t" // vf4 = this
|
||||
"lqc2 vf5, 0x0(%2) \n\t" // vf5 = v
|
||||
|
||||
"vmulz.y vf6, vf4, vf5 \n\t" // vf6.y = vf4.y * vf5.z
|
||||
"vmuly.z vf6, vf4, vf5 \n\t"
|
||||
"vsubz.y vf6, vf6, vf6 \n\t" // vf6.y = vf4.y - vf4.z
|
||||
"vaddy.x vf8, vf0, vf6 \n\t" // res.x = vf4.y * vf5.z - vf4.z * vf5.y
|
||||
|
||||
"vmulx.z vf6, vf4, vf5 \n\t"
|
||||
"vmulz.x vf6, vf4, vf5 \n\t"
|
||||
"vsubx.z vf6, vf6, vf6 \n\t"
|
||||
"vaddz.y vf8, vf0, vf6 \n\t" // res.y = vf4.z * vf5.x - vf4.x * vf5.z
|
||||
|
||||
"vmuly.x vf6, vf4, vf5 \n\t"
|
||||
"vmulx.y vf6, vf4, vf5 \n\t"
|
||||
"vsuby.x vf6, vf6, vf6 \n\t"
|
||||
"vaddx.z vf8, vf0, vf6 \n\t" // res.z = vf4.x * vf5.y - vf4.y * vf5.x
|
||||
"sqc2 vf8, 0x0(%0) \n\t"
|
||||
:
|
||||
: "r"(res.xyz), "r"(this->xyz), "r"(v.xyz));
|
||||
// result.x = y * v.z - z * v.y;
|
||||
// result.y = z * v.x - x * v.z;
|
||||
// result.z = x * v.y - y * v.x;
|
||||
return res;
|
||||
}
|
||||
|
||||
Vector3 Vector3::operator*(float t)
|
||||
{
|
||||
Vector3 result;
|
||||
asm volatile(
|
||||
"lqc2 vf4, 0x0(%1) \n\t"
|
||||
"mfc1 $8, %2 \n\t"
|
||||
"qmtc2 $8, vf5 \n\t"
|
||||
"vmulx.xyz vf6, vf4, vf5 \n\t"
|
||||
"sqc2 vf6, 0x0(%0) \n\t"
|
||||
:
|
||||
: "r"(result.xyz), "r"(this->xyz), "f"(t)
|
||||
: "$8");
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector3 Vector3::operator/(float t)
|
||||
{
|
||||
Vector3 result;
|
||||
result.x = x / t;
|
||||
result.y = y / t;
|
||||
result.z = z / t;
|
||||
return result;
|
||||
}
|
||||
|
||||
u8 Vector3::shouldBeBackfaceCulled(const Vector3 *t_cameraPos, const Vector3 *v0, const Vector3 *v1, const Vector3 *v2)
|
||||
{
|
||||
register float dot;
|
||||
asm volatile(
|
||||
"lqc2 vf4, 0x0(%1) \n\t" // vf4 = cameraPos
|
||||
"lqc2 vf5, 0x0(%2) \n\t" // vf5 = v0
|
||||
"lqc2 vf6, 0x0(%3) \n\t" // vf6 = v1
|
||||
"lqc2 vf7, 0x0(%4) \n\t" // vf7 = v2
|
||||
"vsub.xyz vf8, vf7, vf5 \n\t" // vf8 = vf7(v2) - vf5(v0)
|
||||
"vsub.xyz vf9, vf6, vf5 \n\t" // vf9 = vf6(v1) - vf5(v0)
|
||||
"vopmula.xyz ACC, vf8, vf9 \n\t" // vf6 = cross(vf8, vf9)
|
||||
"vopmsub.xyz vf6, vf9, vf8 \n\t"
|
||||
"vsub.w vf6, vf6, vf6 \n\t"
|
||||
"vsub.xyz vf7, vf5, vf4 \n\t" // vf7 = vf5(v0) - vf4(cameraPos)
|
||||
"vmul.xyz vf5, vf7, vf6 \n\t" // vf5 = dot(vf7, vf6)
|
||||
"vaddy.x vf5, vf5, vf5 \n\t"
|
||||
"vaddz.x vf5, vf5, vf5 \n\t"
|
||||
"qmfc2 $2, vf5 \n\t" // store result on `dot` variable
|
||||
"mtc1 $2, %0 \n\t"
|
||||
: "=f"(dot)
|
||||
: "r"(t_cameraPos->xyz), "r"(v0->xyz), "r"(v1->xyz), "r"(v2->xyz)
|
||||
: "$2");
|
||||
return dot <= 0.0F;
|
||||
}
|
||||
|
||||
/** Checks intersection with given square */
|
||||
u8 Vector3::collidesSquare(Vector3 &t_min, Vector3 &t_max)
|
||||
{
|
||||
return ((this->x <= t_max.x && this->x >= t_min.x) && (this->y < t_max.y && this->y >= t_min.y) && (this->z <= t_max.z && this->z >= t_min.z)) ? 1 : 0;
|
||||
}
|
||||
|
||||
/** Checks is this vector is on given square */
|
||||
u8 Vector3::isOnSquare(Vector3 &t_min, Vector3 &t_max)
|
||||
{
|
||||
return ((this->x <= t_max.x && this->x >= t_min.x) && (this->y >= t_max.y) && (this->z <= t_max.z && this->z >= t_min.z)) ? 1 : 0;
|
||||
}
|
||||
|
||||
float Vector3::length()
|
||||
{
|
||||
register float result;
|
||||
asm volatile( // VU0 Macro program
|
||||
"lqc2 vf4, 0x0(%1) \n\t"
|
||||
"vmul.xyz vf5, vf4, vf4 \n\t"
|
||||
"vaddy.x vf5, vf5, vf5 \n\t"
|
||||
"vaddz.x vf5, vf5, vf5 \n\t"
|
||||
"vsqrt Q , vf5x \n\t"
|
||||
"vaddq.x vf8, vf0, Q \n\t"
|
||||
"qmfc2 $2, vf8 \n\t"
|
||||
"mtc1 $2, %0 \n\t"
|
||||
: "=f"(result)
|
||||
: "r"(this->xyz)
|
||||
: "$2");
|
||||
return result;
|
||||
// return Math::sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
void Vector3::normalize()
|
||||
{
|
||||
asm volatile( // VU0 Macro program
|
||||
"lqc2 vf4, 0x0(%0) \n\t"
|
||||
"vmul.xyz vf5, vf4, vf4 \n\t"
|
||||
"vaddy.x vf5, vf5, vf5 \n\t"
|
||||
"vaddz.x vf5, vf5, vf5 \n\t"
|
||||
"vrsqrt Q, vf0w, vf5x \n\t"
|
||||
"vsub.xyz vf6, vf0, vf0 \n\t"
|
||||
"vaddw.xyz vf6, vf6, vf4 \n\t"
|
||||
"vwaitq \n\t"
|
||||
"vmulq.xyz vf6, vf4, Q \n\t"
|
||||
"sqc2 vf6, 0x0(%0) \n\t"
|
||||
:
|
||||
: "r"(this->xyz));
|
||||
}
|
||||
|
||||
/** Also called dot3 */
|
||||
float Vector3::innerProduct(Vector3 &v)
|
||||
{
|
||||
register float result;
|
||||
asm volatile( // VU0 Macro program
|
||||
"lqc2 vf4, 0x0(%1) \n\t"
|
||||
"lqc2 vf5, 0x0(%2) \n\t"
|
||||
"vmul.xyz vf6, vf4, vf5 \n\t"
|
||||
"vaddy.x vf6, vf6, vf6 \n\t"
|
||||
"vaddz.x vf6, vf6, vf6 \n\t"
|
||||
"qmfc2 $2, vf6 \n\t"
|
||||
"mtc1 $2, %0 \n\t"
|
||||
: "=f"(result)
|
||||
: "r"(this->xyz), "r"(v.xyz)
|
||||
: "$2");
|
||||
return result;
|
||||
// return (x * v.x + y * v.y + z * v.z);
|
||||
}
|
||||
|
||||
void Vector3::set(float x, float y, float z)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->z = z;
|
||||
}
|
||||
|
||||
void Vector3::set(Vector3 &v)
|
||||
{
|
||||
this->x = v.x;
|
||||
this->y = v.y;
|
||||
this->z = v.z;
|
||||
}
|
||||
|
||||
void Vector3::copy(Vector3 &v)
|
||||
{
|
||||
asm volatile( // VU0 Macro program
|
||||
"lq $6, 0x0(%1) \n\t"
|
||||
"sq $6, 0x0(%0) \n\t"
|
||||
:
|
||||
: "r"(v.xyz), "r"(this->xyz)
|
||||
: "$6");
|
||||
}
|
||||
|
||||
float Vector3::distanceTo(Vector3 &v)
|
||||
{
|
||||
register float result;
|
||||
asm volatile( // VU0 Macro program
|
||||
"lqc2 vf4, 0x0(%1) \n\t"
|
||||
"lqc2 vf5, 0x0(%2) \n\t"
|
||||
"vsub.xyz vf6, vf4, vf5 \n\t"
|
||||
"vmul.xyz vf7, vf6, vf6 \n\t"
|
||||
"vaddy.x vf7, vf7, vf7 \n\t"
|
||||
"vaddz.x vf7, vf7, vf7 \n\t"
|
||||
"vsqrt Q , vf7x \n\t"
|
||||
"vaddq.x vf8, vf0, Q \n\t"
|
||||
"qmfc2 $2, vf8 \n\t"
|
||||
"mtc1 $2, %0 \n\t"
|
||||
: "=f"(result)
|
||||
: "r"(this->xyz), "r"(v.xyz)
|
||||
: "$2");
|
||||
return result;
|
||||
// return Math::sqrt((this->x - another.x) * (this->x - another.x) +
|
||||
// (this->y - another.y) * (this->y - another.y) +
|
||||
// (this->z - another.z) * (this->z - another.z));
|
||||
}
|
||||
|
||||
void Vector3::print()
|
||||
{
|
||||
printf("Vector3(%f, %f, %f)\n", x, y, z);
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/models/md2_model.hpp"
|
||||
|
||||
#include "../include/utils/anorms.hpp"
|
||||
#include "../include/utils/string.hpp"
|
||||
#include "../include/utils/debug.hpp"
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
MD2Model::MD2Model(char *t_md2File)
|
||||
{
|
||||
filename = String::createWithoutExtension(t_md2File);
|
||||
|
||||
verticesPerFrameCount = 0;
|
||||
coordinatesCount = 0;
|
||||
trianglesCount = 0;
|
||||
framesCount = 0;
|
||||
|
||||
animState.startFrame = 0;
|
||||
animState.endFrame = 0;
|
||||
animState.interpolation = 0.0F;
|
||||
animState.animType = 0;
|
||||
animState.currentFrame = 0;
|
||||
animState.nextFrame = 0;
|
||||
animState.speed = 0.1F;
|
||||
|
||||
vertices = 0;
|
||||
coordinates = 0;
|
||||
normalIndexes = 0;
|
||||
triangles = 0;
|
||||
}
|
||||
|
||||
MD2Model::~MD2Model()
|
||||
{
|
||||
delete[] vertices;
|
||||
delete[] normalIndexes;
|
||||
delete[] coordinates;
|
||||
delete[] triangles;
|
||||
}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
u32 MD2Model::getCurrentFrameData(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, Vector3 &t_cameraPos, float t_scale, u8 t_shouldBeBackfaceCulled)
|
||||
{
|
||||
u32 i = 0;
|
||||
animState.interpolation += animState.speed;
|
||||
if (animState.interpolation >= 1.0F)
|
||||
{
|
||||
animState.interpolation = 0.0F;
|
||||
animState.currentFrame = animState.nextFrame;
|
||||
if (++animState.nextFrame > animState.endFrame)
|
||||
animState.nextFrame = animState.startFrame;
|
||||
}
|
||||
for (u32 iTri = 0; iTri < trianglesCount; iTri++)
|
||||
{
|
||||
for (u32 iVert = 0; iVert < 3; iVert++)
|
||||
{
|
||||
const u32 CURR_VERTICE =
|
||||
triangles[iTri].verticeIndexes[iVert] +
|
||||
(verticesPerFrameCount * animState.currentFrame);
|
||||
|
||||
if (animState.startFrame == animState.endFrame)
|
||||
{
|
||||
calc3Vectors[iVert].x = vertices[CURR_VERTICE].x * t_scale;
|
||||
calc3Vectors[iVert].y = vertices[CURR_VERTICE].y * t_scale;
|
||||
calc3Vectors[iVert].z = vertices[CURR_VERTICE].z * t_scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
const u32 NEXT_VERTICE =
|
||||
triangles[iTri].verticeIndexes[iVert] +
|
||||
(verticesPerFrameCount * animState.nextFrame);
|
||||
calcVector.setByLerp(vertices[CURR_VERTICE], vertices[NEXT_VERTICE], animState.interpolation);
|
||||
calc3Vectors[iVert].x = calcVector.x * t_scale;
|
||||
calc3Vectors[iVert].y = calcVector.y * t_scale;
|
||||
calc3Vectors[iVert].z = calcVector.z * t_scale;
|
||||
}
|
||||
}
|
||||
if (!t_shouldBeBackfaceCulled || Vector3::shouldBeBackfaceCulled(&t_cameraPos, &calc3Vectors[2], &calc3Vectors[1], &calc3Vectors[0]) == 0)
|
||||
for (u32 iVert = 0; iVert < 3; iVert++)
|
||||
{
|
||||
const u32 CURR_VERTICE =
|
||||
triangles[iTri].verticeIndexes[iVert] +
|
||||
(verticesPerFrameCount * animState.currentFrame);
|
||||
|
||||
const u32 CURR_COORD = triangles[iTri].coordIndexes[iVert];
|
||||
|
||||
o_vertices[i][0] = calc3Vectors[iVert].x;
|
||||
o_vertices[i][1] = calc3Vectors[iVert].y;
|
||||
o_vertices[i][2] = calc3Vectors[iVert].z;
|
||||
o_vertices[i][3] = 1.0F;
|
||||
|
||||
o_normals[i][0] = ANORMS[normalIndexes[CURR_VERTICE]][0];
|
||||
o_normals[i][1] = ANORMS[normalIndexes[CURR_VERTICE]][1];
|
||||
o_normals[i][2] = ANORMS[normalIndexes[CURR_VERTICE]][2];
|
||||
o_normals[i][3] = 1.0F;
|
||||
|
||||
o_coordinates[i][0] = coordinates[CURR_COORD].x;
|
||||
o_coordinates[i][1] = 1.0F - coordinates[CURR_COORD].y;
|
||||
o_coordinates[i][2] = 1.0F;
|
||||
o_coordinates[i][3] = 1.0F;
|
||||
|
||||
o_colors[i][0] = 1.0F;
|
||||
o_colors[i][1] = 1.0F;
|
||||
o_colors[i][2] = 1.0F;
|
||||
o_colors[i][3] = 1.0F;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void MD2Model::allocateMemory()
|
||||
{
|
||||
vertices = new Vector3[verticesPerFrameCount * framesCount];
|
||||
normalIndexes = new u32[verticesPerFrameCount * framesCount];
|
||||
coordinates = new Point[coordinatesCount];
|
||||
triangles = new MD2Triangle[trianglesCount];
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/models/mesh.hpp"
|
||||
|
||||
#include "../include/loaders/obj_loader.hpp"
|
||||
#include "../include/loaders/md2_loader.hpp"
|
||||
#include "../include/loaders/dff_loader.hpp"
|
||||
#include "../include/loaders/bmp_loader.hpp"
|
||||
#include "../include/utils/debug.hpp"
|
||||
#include "../include/utils/string.hpp"
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
Mesh::Mesh()
|
||||
{
|
||||
shouldBeFrustumCulled = true;
|
||||
shouldBeBackfaceCulled = false;
|
||||
shouldBeLighted = false;
|
||||
isMd2Loaded = false;
|
||||
isObjLoaded = false;
|
||||
isDffLoaded = false;
|
||||
isSpecInitialized = false;
|
||||
scale = 1.0F;
|
||||
}
|
||||
|
||||
Mesh::~Mesh()
|
||||
{
|
||||
if (isMd2Loaded)
|
||||
delete md2;
|
||||
if (isObjLoaded)
|
||||
delete obj;
|
||||
if (isDffLoaded)
|
||||
delete dff;
|
||||
}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
void Mesh::loadDff(char *t_subfolder, char *t_dffFile, Vector3 &t_initPos, float t_scale)
|
||||
{
|
||||
createSpecIfNotCreated();
|
||||
DffLoader loader = DffLoader();
|
||||
dff = new DffModel();
|
||||
char *dffPath = String::createConcatenated(t_subfolder, t_dffFile);
|
||||
loader.load(dff->clump, dffPath, t_scale);
|
||||
delete[] dffPath;
|
||||
position = t_initPos;
|
||||
setVerticesReference(
|
||||
dff->clump.geometryList.geometries[0].data.dataHeader.vertexCount,
|
||||
dff->clump.geometryList.geometries[0].data.vertexInformation);
|
||||
setDefaultColor();
|
||||
isDffLoaded = true;
|
||||
loadTextures(t_subfolder, ".bmp");
|
||||
spec->allocateTextureBuffer(spec->textures[0].width, spec->textures[0].height); // wtf?
|
||||
}
|
||||
|
||||
void Mesh::setDff(Vector3 &t_initPos, DffModel *t_dffModel, MeshSpec *t_spec)
|
||||
{
|
||||
position = t_initPos;
|
||||
spec = t_spec;
|
||||
isSpecInitialized = 1;
|
||||
dff = t_dffModel;
|
||||
setVerticesReference(
|
||||
dff->clump.geometryList.geometries[0].data.dataHeader.vertexCount,
|
||||
dff->clump.geometryList.geometries[0].data.vertexInformation);
|
||||
setDefaultColor();
|
||||
isDffLoaded = true;
|
||||
}
|
||||
|
||||
void Mesh::loadObj(char *t_subfolder, char *t_objFile, Vector3 &t_initPos, float t_scale)
|
||||
{
|
||||
createSpecIfNotCreated();
|
||||
ObjLoader loader = ObjLoader();
|
||||
obj = new ObjModel(t_objFile);
|
||||
char *objPath = String::createConcatenated(t_subfolder, t_objFile);
|
||||
loader.load(obj, objPath, t_scale);
|
||||
delete[] objPath;
|
||||
position = t_initPos;
|
||||
setVerticesReference(obj->facesCount, obj->vertices);
|
||||
setDefaultColor();
|
||||
isObjLoaded = true;
|
||||
loadTextures(t_subfolder, ".bmp");
|
||||
spec->allocateTextureBuffer(spec->textures[0].width, spec->textures[0].height); // wtf?
|
||||
}
|
||||
|
||||
void Mesh::setObj(Vector3 &t_initPos, ObjModel *t_objModel, MeshSpec *t_spec)
|
||||
{
|
||||
position = t_initPos;
|
||||
spec = t_spec;
|
||||
isSpecInitialized = true;
|
||||
obj = t_objModel;
|
||||
setVerticesReference(obj->facesCount, obj->vertices);
|
||||
setDefaultColor();
|
||||
isObjLoaded = true;
|
||||
}
|
||||
|
||||
void Mesh::createSpecIfNotCreated()
|
||||
{
|
||||
if (!isSpecInitialized)
|
||||
{
|
||||
isSpecInitialized = true;
|
||||
spec = new MeshSpec();
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::setAnimSpeed(float t_value)
|
||||
{
|
||||
if (isMd2Loaded == 1)
|
||||
md2->animState.speed = t_value;
|
||||
else
|
||||
PRINT_ERR("Animation speed set is not possible, because no md2 3D model was loaded!");
|
||||
}
|
||||
|
||||
void Mesh::setVerticesReference(u32 t_verticesCount, Vector3 *t_verticesRef)
|
||||
{
|
||||
verticesCount = t_verticesCount;
|
||||
vertices = t_verticesRef;
|
||||
computeBoundingBox();
|
||||
}
|
||||
|
||||
u32 Mesh::getVertexCount()
|
||||
{
|
||||
if (isMd2Loaded)
|
||||
return md2->trianglesCount * 3;
|
||||
else if (isObjLoaded)
|
||||
return obj->facesCount;
|
||||
else if (isDffLoaded)
|
||||
return dff->clump.geometryList.geometries[0].data.dataHeader.triangleCount * 3;
|
||||
else
|
||||
{
|
||||
PRINT_ERR("Can't get vertex count, because no 3D model was loaded!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::setDefaultWrapSettings(texwrap_t &t_wrapSettings)
|
||||
{
|
||||
t_wrapSettings.horizontal = WRAP_REPEAT;
|
||||
t_wrapSettings.vertical = WRAP_REPEAT;
|
||||
t_wrapSettings.maxu = 0;
|
||||
t_wrapSettings.maxv = 0;
|
||||
t_wrapSettings.minu = 0;
|
||||
t_wrapSettings.minv = 0;
|
||||
}
|
||||
|
||||
void Mesh::loadTextures(char *t_subfolder, char *t_extension)
|
||||
{
|
||||
BmpLoader bmpLoader = BmpLoader();
|
||||
if (isMd2Loaded || isObjLoaded)
|
||||
{
|
||||
spec->textures = new Texture[1];
|
||||
if (isMd2Loaded)
|
||||
bmpLoader.load(spec->textures[0], t_subfolder, md2->filename, t_extension);
|
||||
if (isObjLoaded)
|
||||
bmpLoader.load(spec->textures[0], t_subfolder, obj->filename, t_extension);
|
||||
setDefaultWrapSettings(spec->textures[0].wrapSettings);
|
||||
}
|
||||
else if (isDffLoaded)
|
||||
{
|
||||
spec->textures = new Texture[dff->clump.geometryList.geometries[0].materialList.data.materialCount];
|
||||
for (u8 i = 0; i < dff->clump.geometryList.geometries[0].materialList.data.materialCount; i++)
|
||||
for (u8 j = 0; j < dff->clump.geometryList.geometries[0].materialList.materials[i].data.textureCount; j++)
|
||||
{
|
||||
bmpLoader.load(spec->textures[i], t_subfolder, dff->clump.geometryList.geometries[0].materialList.materials[i].textures[j].textureName.text, t_extension);
|
||||
setDefaultWrapSettings(spec->textures[i].wrapSettings);
|
||||
}
|
||||
}
|
||||
else
|
||||
PRINT_ERR("Can't load textures, because no 3D model was loaded!");
|
||||
}
|
||||
|
||||
// TODO refactor
|
||||
u32 Mesh::getDrawData(u32 splitIndex, VECTOR *t_vertices, VECTOR *t_normals, VECTOR *t_coordinates, VECTOR *t_colors, Vector3 &t_cameraPos)
|
||||
{
|
||||
if (isMd2Loaded)
|
||||
return md2->getCurrentFrameData(t_vertices, t_normals, t_coordinates, t_colors, t_cameraPos, scale, shouldBeBackfaceCulled);
|
||||
else if (isObjLoaded)
|
||||
return obj->getDrawData(t_vertices, t_normals, t_coordinates, t_colors, t_cameraPos, scale, shouldBeBackfaceCulled);
|
||||
else if (isDffLoaded)
|
||||
return dff->getDrawData(splitIndex, t_vertices, t_normals, t_coordinates, t_colors, t_cameraPos, scale, shouldBeBackfaceCulled);
|
||||
PRINT_ERR("Can't get draw data, because no 3D model was loaded!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Set object position and specification */
|
||||
void Mesh::loadMD2(char *t_subfolder, char *t_md2File, Vector3 &t_initPos, float t_scale)
|
||||
{
|
||||
createSpecIfNotCreated();
|
||||
md2 = new MD2Model(t_md2File);
|
||||
MD2Loader loader = MD2Loader();
|
||||
position = t_initPos;
|
||||
char *md2Path = String::createConcatenated(t_subfolder, t_md2File);
|
||||
loader.load(md2, md2Path, t_scale);
|
||||
delete[] md2Path;
|
||||
setVerticesReference(md2->verticesPerFrameCount * md2->framesCount, md2->vertices);
|
||||
setDefaultColor();
|
||||
isMd2Loaded = true;
|
||||
loadTextures(t_subfolder, ".bmp");
|
||||
spec->allocateTextureBuffer(spec->textures[0].width, spec->textures[0].height); // wtf?
|
||||
}
|
||||
|
||||
/** Set's default object color + no transparency */
|
||||
void Mesh::setDefaultColor()
|
||||
{
|
||||
color.r = 0x80;
|
||||
color.g = 0x80;
|
||||
color.b = 0x80;
|
||||
color.a = 0x80;
|
||||
color.q = 1.0F;
|
||||
}
|
||||
|
||||
/** Calculates minimum and maximum X, Y, Z of this 3D objects vertices + current position */
|
||||
void Mesh::getMinMax(Vector3 *t_min, Vector3 *t_max)
|
||||
{
|
||||
Vector3 calc = Vector3();
|
||||
u8 isInitialized = 0;
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
getFarthestVertex(&calc, i);
|
||||
if (isInitialized == 0)
|
||||
{
|
||||
isInitialized = 1;
|
||||
t_min->set(calc);
|
||||
t_max->set(calc);
|
||||
}
|
||||
|
||||
if (t_min->x > calc.x)
|
||||
t_min->x = calc.x;
|
||||
if (calc.x > t_max->x)
|
||||
t_max->x = calc.x;
|
||||
|
||||
if (t_min->y > calc.y)
|
||||
t_min->y = calc.y;
|
||||
if (calc.y > t_max->y)
|
||||
t_max->y = calc.y;
|
||||
|
||||
if (t_min->z > calc.z)
|
||||
t_min->z = calc.z;
|
||||
if (calc.z > t_max->z)
|
||||
t_max->z = calc.z;
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::playAnimation(u32 t_startFrame, u32 t_endFrame)
|
||||
{
|
||||
if (isMd2Loaded == 1)
|
||||
{
|
||||
md2->animState.startFrame = t_startFrame;
|
||||
md2->animState.endFrame = t_endFrame;
|
||||
}
|
||||
else
|
||||
PRINT_ERR("Animation is only supported in MD2 format!");
|
||||
}
|
||||
|
||||
/** Returns next farthest vertex of 3D object
|
||||
* @param offset Max 8 (because, box have 8 corners)
|
||||
*/
|
||||
void Mesh::getFarthestVertex(Vector3 *o_result, int t_offset)
|
||||
{
|
||||
o_result->x = boxVertices[t_offset].x + position.x;
|
||||
o_result->y = boxVertices[t_offset].y + position.y;
|
||||
o_result->z = boxVertices[t_offset].z + position.z;
|
||||
}
|
||||
|
||||
/** Check if box is visible in view frustum */
|
||||
u8 Mesh::isInFrustum(Plane *t_frustumPlanes)
|
||||
{
|
||||
Vector3 boxCalcTemp;
|
||||
int boxResult = 1, boxIn = 0, boxOut = 0;
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
boxOut = 0;
|
||||
boxIn = 0;
|
||||
// for each corner of the box do ...
|
||||
// get out of the cycle as soon as a box as corners
|
||||
// both inside and out of the frustum
|
||||
for (int y = 0; y < 8 && (boxIn == 0 || boxOut == 0); y++)
|
||||
{
|
||||
getFarthestVertex(&boxCalcTemp, y);
|
||||
if (t_frustumPlanes[i].distanceTo(boxCalcTemp) < 0)
|
||||
boxOut++;
|
||||
else
|
||||
boxIn++;
|
||||
}
|
||||
//if all corners are out
|
||||
if (boxIn == 0)
|
||||
return 0;
|
||||
else if (boxOut)
|
||||
boxResult = 1;
|
||||
}
|
||||
return boxResult;
|
||||
}
|
||||
|
||||
/** Compute 8 farthest corners for intersection check */
|
||||
void Mesh::computeBoundingBox()
|
||||
{
|
||||
float lowX, lowY, lowZ, hiX, hiY, hiZ;
|
||||
lowX = hiX = vertices[0].x;
|
||||
lowY = hiY = vertices[0].y;
|
||||
lowZ = hiZ = vertices[0].z;
|
||||
for (u32 i = 0; i < verticesCount; i++)
|
||||
{
|
||||
if (lowX > vertices[i].x)
|
||||
lowX = vertices[i].x;
|
||||
if (hiX < vertices[i].x)
|
||||
hiX = vertices[i].x;
|
||||
|
||||
if (lowY > vertices[i].y)
|
||||
lowY = vertices[i].y;
|
||||
if (hiY < vertices[i].y)
|
||||
hiY = vertices[i].y;
|
||||
|
||||
if (lowZ > vertices[i].z)
|
||||
lowZ = vertices[i].z;
|
||||
if (hiZ < vertices[i].z)
|
||||
hiZ = vertices[i].z;
|
||||
}
|
||||
boxVertices[0].set(lowX, lowY, lowZ);
|
||||
boxVertices[1].set(lowX, lowY, hiZ);
|
||||
boxVertices[2].set(lowX, hiY, lowZ);
|
||||
boxVertices[3].set(lowX, hiY, hiZ);
|
||||
|
||||
boxVertices[4].set(hiX, lowY, lowZ);
|
||||
boxVertices[5].set(hiX, lowY, hiZ);
|
||||
boxVertices[6].set(hiX, hiY, lowZ);
|
||||
boxVertices[7].set(hiX, hiY, hiZ);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/models/mesh_spec.hpp"
|
||||
|
||||
#include "../include/utils/debug.hpp"
|
||||
#include "../include/utils/math.hpp"
|
||||
#include <graph_vram.h>
|
||||
#include <gs_psm.h>
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
MeshSpec::MeshSpec()
|
||||
{
|
||||
PRINT_LOG("Creating object 3D spec");
|
||||
this->setupLodAndClut();
|
||||
PRINT_LOG("Object 3D spec created!");
|
||||
}
|
||||
|
||||
/** Release memory if object was initialized */
|
||||
MeshSpec::~MeshSpec()
|
||||
{
|
||||
if (this->isTextureVRAMAllocated == true)
|
||||
graph_vram_free(this->textureBuffer.address);
|
||||
}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
/** Configure and allocate vRAM for texture buffer */
|
||||
void MeshSpec::allocateTextureBuffer(u16 t_width, u16 t_height)
|
||||
{
|
||||
this->textureBuffer.width = t_width;
|
||||
this->textureBuffer.psm = GS_PSM_24;
|
||||
this->textureBuffer.address = graph_vram_allocate(t_width, t_height, GS_PSM_24, GRAPH_ALIGN_BLOCK);
|
||||
if (this->textureBuffer.address <= 1)
|
||||
PRINT_ERR("Texture buffer allocation error. No memory!");
|
||||
this->textureBuffer.info.width = draw_log2(t_width);
|
||||
this->textureBuffer.info.height = draw_log2(t_height);
|
||||
this->textureBuffer.info.components = TEXTURE_COMPONENTS_RGB;
|
||||
this->textureBuffer.info.function = TEXTURE_FUNCTION_MODULATE;
|
||||
this->isTextureVRAMAllocated = true;
|
||||
}
|
||||
|
||||
/** Configure and allocate vRAM for texture buffer */
|
||||
void MeshSpec::deallocateTextureBuffer()
|
||||
{
|
||||
if (this->isTextureVRAMAllocated)
|
||||
{
|
||||
graph_vram_free(textureBuffer.address);
|
||||
this->isTextureVRAMAllocated = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets texture level of details settings and CLUT settings */
|
||||
void MeshSpec::setupLodAndClut()
|
||||
{
|
||||
PRINT_LOG("Setting LOD, CLUT");
|
||||
this->lod.calculation = LOD_USE_K;
|
||||
this->lod.max_level = 0;
|
||||
this->lod.mag_filter = LOD_MAG_NEAREST;
|
||||
this->lod.min_filter = LOD_MIN_NEAREST;
|
||||
this->lod.l = 0;
|
||||
this->lod.k = 0.0F;
|
||||
|
||||
this->clut.storage_mode = CLUT_STORAGE_MODE1;
|
||||
this->clut.start = 0;
|
||||
this->clut.psm = 0;
|
||||
this->clut.load_method = CLUT_NO_LOAD;
|
||||
this->clut.address = 0;
|
||||
PRINT_LOG("LOD, CLUT set!");
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/models/obj_model.hpp"
|
||||
|
||||
#include "../include/utils/debug.hpp"
|
||||
#include "../include/utils/string.hpp"
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
ObjModel::ObjModel(char *t_objFile)
|
||||
{
|
||||
filename = String::createWithoutExtension(t_objFile);
|
||||
}
|
||||
|
||||
ObjModel::~ObjModel()
|
||||
{
|
||||
if (isMemoryAllocated == true)
|
||||
{
|
||||
delete[] vertices;
|
||||
delete[] coordinates;
|
||||
delete[] normals;
|
||||
|
||||
delete[] verticeFaces;
|
||||
delete[] coordinateFaces;
|
||||
delete[] normalFaces;
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
u32 ObjModel::getDrawData(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, Vector3 &t_cameraPos, float t_scale, u8 t_shouldBeBackfaceCulled)
|
||||
{
|
||||
u32 addedFaces = 0;
|
||||
for (u32 i = 0; i < facesCount; i += 3)
|
||||
if (!t_shouldBeBackfaceCulled || Vector3::shouldBeBackfaceCulled(
|
||||
&t_cameraPos,
|
||||
&vertices[verticeFaces[i]],
|
||||
&vertices[verticeFaces[i + 1]],
|
||||
&vertices[verticeFaces[i + 2]]) == 0)
|
||||
{
|
||||
fillNextFace(o_vertices, o_normals, o_coordinates, o_colors, i, addedFaces++);
|
||||
fillNextFace(o_vertices, o_normals, o_coordinates, o_colors, i + 1, addedFaces++);
|
||||
fillNextFace(o_vertices, o_normals, o_coordinates, o_colors, i + 2, addedFaces++);
|
||||
}
|
||||
|
||||
return addedFaces;
|
||||
}
|
||||
|
||||
/** Allocate memory for vertices,coords etc.
|
||||
* Called by ObjLoader
|
||||
*/
|
||||
void ObjModel::allocateMemory()
|
||||
{
|
||||
PRINT_LOG("Allocating 3D object specification memory");
|
||||
vertices = new Vector3[verticesCount];
|
||||
coordinates = new Vector3[coordinatesCount];
|
||||
normals = new Vector3[normalsCount];
|
||||
|
||||
verticeFaces = new u32[facesCount];
|
||||
coordinateFaces = new u32[facesCount];
|
||||
normalFaces = new u32[facesCount];
|
||||
isMemoryAllocated = true;
|
||||
PRINT_LOG("3D object specification memory allocated!");
|
||||
}
|
||||
|
||||
void ObjModel::fillNextFace(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, u32 t_getI, u32 t_setI)
|
||||
{
|
||||
o_vertices[t_setI][0] = vertices[verticeFaces[t_getI]].x;
|
||||
o_vertices[t_setI][1] = vertices[verticeFaces[t_getI]].y;
|
||||
o_vertices[t_setI][2] = vertices[verticeFaces[t_getI]].z;
|
||||
o_vertices[t_setI][3] = 1.0F;
|
||||
|
||||
o_normals[t_setI][0] = normals[normalFaces[t_getI]].x;
|
||||
o_normals[t_setI][1] = normals[normalFaces[t_getI]].y;
|
||||
o_normals[t_setI][2] = normals[normalFaces[t_getI]].z;
|
||||
o_normals[t_setI][3] = 1.0F;
|
||||
|
||||
o_coordinates[t_setI][0] = coordinates[coordinateFaces[t_getI]].x;
|
||||
o_coordinates[t_setI][1] = coordinates[coordinateFaces[t_getI]].y;
|
||||
o_coordinates[t_setI][2] = 1.0F;
|
||||
o_coordinates[t_setI][3] = 1.0F;
|
||||
|
||||
o_colors[t_setI][0] = 1.0F;
|
||||
o_colors[t_setI][1] = 1.0F;
|
||||
o_colors[t_setI][2] = 1.0F;
|
||||
o_colors[t_setI][3] = 1.0F;
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/modules/audio.hpp"
|
||||
|
||||
#include <loadfile.h>
|
||||
#include "../include/utils/string.hpp"
|
||||
#include "../include/utils/debug.hpp"
|
||||
|
||||
#define SONG_NAME "MOV-CIRC.WAV"
|
||||
const int AUDSRV_BUFFER_SIZE = 1024 * 4;
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
Audio *audioRef;
|
||||
|
||||
Audio::Audio()
|
||||
{
|
||||
addedListeners = 0;
|
||||
isInitialized = 0;
|
||||
songLoaded = 0;
|
||||
isVolumeSet = 0;
|
||||
shouldPlay = 0;
|
||||
audioRef = this;
|
||||
initSema();
|
||||
loadModules();
|
||||
initAUDSRV();
|
||||
}
|
||||
|
||||
Audio::~Audio() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
/** Initialize audio module
|
||||
*
|
||||
* - Initialize threading semaphore
|
||||
* - Load modules
|
||||
* - Initialize AUDSRV
|
||||
* - Load background song
|
||||
*/
|
||||
void Audio::init(u32 t_listenersAmount)
|
||||
{
|
||||
PRINT_LOG("Initialize audio module started");
|
||||
listenersAmount = t_listenersAmount;
|
||||
listeners = new AudioListener *[t_listenersAmount];
|
||||
isInitialized = true;
|
||||
PRINT_LOG("Audio module initialized!");
|
||||
}
|
||||
|
||||
void Audio::addListener(AudioListener *t_listener)
|
||||
{
|
||||
listeners[addedListeners++] = t_listener;
|
||||
}
|
||||
|
||||
/** Initialize threading semaphore */
|
||||
void Audio::initSema()
|
||||
{
|
||||
PRINT_LOG("Creating semaphore started");
|
||||
sema.init_count = 0;
|
||||
sema.max_count = 1;
|
||||
sema.option = 0;
|
||||
fillbufferSema = CreateSema(&sema);
|
||||
PRINT_LOG("Semaphore created");
|
||||
}
|
||||
|
||||
/** Load LIBSD and AUDSRV */
|
||||
void Audio::loadModules()
|
||||
{
|
||||
PRINT_LOG("Modules loading started (LIBSD, AUDSRV)");
|
||||
ret = SifLoadModule("rom0:LIBSD", 0, NULL);
|
||||
ret = SifLoadModule("host:AUDSRV.IRX", 0, NULL);
|
||||
PRINT_LOG("Modules loaded");
|
||||
}
|
||||
|
||||
/** Initialize AUDSRV and install fillbuffer callback */
|
||||
void Audio::initAUDSRV()
|
||||
{
|
||||
PRINT_LOG("Initialize AUDSRV started");
|
||||
ret = audsrv_init();
|
||||
if (ret != 0)
|
||||
{
|
||||
PRINT_ERR("Failed to initialize AUDSRV!");
|
||||
printf("AUDSRV returned error string: %s", audsrv_get_error_string());
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = audsrv_on_fillbuf(AUDSRV_BUFFER_SIZE, Audio::fillbuffer, (void *)fillbufferSema);
|
||||
PRINT_LOG("AUDSRV initialized!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Set audio format, volume and load song */
|
||||
void Audio::loadSong(char *t_filename)
|
||||
{
|
||||
if (!isInitialized)
|
||||
{
|
||||
PRINT_ERR("Please initialize audio class first!");
|
||||
return;
|
||||
}
|
||||
PRINT_LOG("Song loading started");
|
||||
format.bits = 16;
|
||||
format.freq = 22050;
|
||||
format.channels = 2;
|
||||
char *fullFilename = String::createConcatenated("host:", t_filename);
|
||||
int err = audsrv_set_format(&format);
|
||||
if (err == 0)
|
||||
{
|
||||
PRINT_LOG("Audio format set");
|
||||
if (!isVolumeSet)
|
||||
setVolume(MAX_VOLUME);
|
||||
PRINT_LOG("Opening song file: " SONG_NAME);
|
||||
wav = fopen(fullFilename, "rb");
|
||||
delete[] fullFilename;
|
||||
if (wav == NULL)
|
||||
{
|
||||
PRINT_ERR("Failed to open wav file!");
|
||||
audsrv_quit();
|
||||
}
|
||||
else
|
||||
{
|
||||
fseek(wav, 0x30, SEEK_SET);
|
||||
played = 0;
|
||||
songLoaded = 1;
|
||||
PRINT_LOG("Song loaded!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT_ERR("Failed to set audio format!");
|
||||
printf("AUDSRV returned error string: %s", audsrv_get_error_string());
|
||||
}
|
||||
}
|
||||
|
||||
void Audio::setVolume(u8 t_volume)
|
||||
{
|
||||
audsrv_set_volume(t_volume);
|
||||
isVolumeSet = true;
|
||||
}
|
||||
|
||||
/** Create and start audio thread. */
|
||||
void Audio::startThread()
|
||||
{
|
||||
PRINT_LOG("Creating audio thread");
|
||||
extern void *_gp;
|
||||
audioThreadAttr.func = (void *)Audio::audioThread;
|
||||
audioThreadAttr.stack = audioThreadStack;
|
||||
audioThreadAttr.stack_size = STACK_SIZE;
|
||||
audioThreadAttr.gp_reg = (void *)&_gp;
|
||||
audioThreadAttr.initial_priority = 0x17;
|
||||
if ((audioThreadId = CreateThread(&audioThreadAttr)) < 0)
|
||||
PRINT_ERR("Create audio thread failed!");
|
||||
PRINT_LOG("Audio thread created");
|
||||
StartThread(audioThreadId, NULL);
|
||||
PRINT_LOG("Audio thread started");
|
||||
}
|
||||
|
||||
/** Do not call this function.
|
||||
* This is a audio thread, runned by AudioThread::start()
|
||||
*/
|
||||
void Audio::audioThread()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (audioRef->shouldPlay)
|
||||
audioRef->work();
|
||||
}
|
||||
}
|
||||
|
||||
void Audio::play()
|
||||
{
|
||||
if (!isInitialized)
|
||||
{
|
||||
PRINT_ERR("Please initialize audio class first!");
|
||||
return;
|
||||
}
|
||||
shouldPlay = 1;
|
||||
}
|
||||
|
||||
void Audio::stop()
|
||||
{
|
||||
if (!isInitialized)
|
||||
{
|
||||
PRINT_ERR("Please initialize audio class first!");
|
||||
return;
|
||||
}
|
||||
shouldPlay = 0;
|
||||
}
|
||||
|
||||
/** Play song and run it again on finish */
|
||||
void Audio::work()
|
||||
{
|
||||
if (!isTrackDone)
|
||||
{
|
||||
ret = fread(chunk, 1, sizeof(chunk), wav);
|
||||
if (ret > 0)
|
||||
{
|
||||
WaitSema(fillbufferSema);
|
||||
audsrv_play_audio(chunk, ret);
|
||||
}
|
||||
if (ret < (int)sizeof(chunk))
|
||||
{
|
||||
isTrackDone = true;
|
||||
return;
|
||||
}
|
||||
played++;
|
||||
if ((played + 20) % 41 == 0 && addedListeners)
|
||||
for (u32 i = 0; i < addedListeners; i++)
|
||||
listeners[i]->onAudioTick();
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT_LOG("Song " SONG_NAME " finished. Running again...");
|
||||
played = 0;
|
||||
fseek(wav, 0x30, SEEK_SET);
|
||||
isTrackDone = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Unload audio module by closing file stream and stopping AUDSRV */
|
||||
void Audio::unloadSong()
|
||||
{
|
||||
PRINT_LOG("Unloading audio module started");
|
||||
fclose(wav);
|
||||
PRINT_LOG("Song file stream closed");
|
||||
audsrv_quit();
|
||||
PRINT_LOG("AUDSRV stopped");
|
||||
PRINT_LOG("Audio module unloaded");
|
||||
}
|
||||
|
||||
/** Do not call this function.
|
||||
* This is a static callback function
|
||||
* for AUDSRV fillbuffer (semaphore)
|
||||
*/
|
||||
int Audio::fillbuffer(void *arg)
|
||||
{
|
||||
iSignalSema((int)arg);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/modules/camera_base.hpp"
|
||||
|
||||
#include <fastmath.h>
|
||||
#include "../include/utils/debug.hpp"
|
||||
#include "../include/utils/math.hpp"
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
/** Initializes vars and calculate width/height of near and far plane
|
||||
* @param fov (FOV in radians)/2
|
||||
* @param ratio Aspect ratio
|
||||
*/
|
||||
CameraBase::CameraBase(ScreenSettings *t_screen, Vector3 *t_position, Vector3 *t_up, Vector3 *t_unitCirclePosition)
|
||||
: screen(t_screen)
|
||||
{
|
||||
PRINT_LOG("Initializing frustum");
|
||||
farPlaneDist = screen->farPlaneDist;
|
||||
nearPlaneDist = screen->nearPlaneDist;
|
||||
float tang = tanf(screen->fov * Math::HALF_ANG2RAD);
|
||||
nearHeight = tang * nearPlaneDist;
|
||||
nearWidth = nearHeight * screen->aspectRatio;
|
||||
farHeight = tang * farPlaneDist;
|
||||
farWidth = farHeight * screen->aspectRatio;
|
||||
position2 = t_position;
|
||||
up2 = t_up;
|
||||
unitCirclePosition2 = t_unitCirclePosition;
|
||||
PRINT_LOG("CameraBase initialized!");
|
||||
}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
/** Calculates and updates frustum planes
|
||||
* http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-extracting-the-planes/
|
||||
*/
|
||||
void CameraBase::updatePlanes(Vector3 t_target)
|
||||
{
|
||||
Vector3 nearCenter, farCenter, X, Y, Z;
|
||||
// compute the Z axis of camera
|
||||
Z = *position2 - t_target;
|
||||
Z.normalize();
|
||||
// X axis of camera of given "up" vector and Z axis
|
||||
X = *up2 * Z;
|
||||
X.normalize();
|
||||
// the real "up" vector is the cross product of Z and X
|
||||
Y = Z * X;
|
||||
// compute the center of the near and far planes
|
||||
nearCenter = *position2 - Z * nearPlaneDist;
|
||||
farCenter = *position2 - Z * farPlaneDist;
|
||||
// compute the 8 corners of the frustum
|
||||
ntl = nearCenter + Y * nearHeight - X * nearWidth;
|
||||
ntr = nearCenter + Y * nearHeight + X * nearWidth;
|
||||
nbl = nearCenter - Y * nearHeight - X * nearWidth;
|
||||
nbr = nearCenter - Y * nearHeight + X * nearWidth;
|
||||
|
||||
ftl = farCenter + Y * farHeight - X * farWidth;
|
||||
fbr = farCenter - Y * farHeight + X * farWidth;
|
||||
ftr = farCenter + Y * farHeight + X * farWidth;
|
||||
fbl = farCenter - Y * farHeight - X * farWidth;
|
||||
|
||||
planes[0].update(ntr, ntl, ftl); // Top
|
||||
planes[1].update(nbl, nbr, fbr); // BOTTOM
|
||||
planes[2].update(ntl, nbl, fbl); // LEFT
|
||||
planes[3].update(nbr, ntr, fbr); // RIGHT
|
||||
planes[4].update(ntl, ntr, nbr); // NEAR
|
||||
planes[5].update(ftr, ftl, fbl); // FAR
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/modules/gif_sender.hpp"
|
||||
|
||||
#include "../include/utils/math.hpp"
|
||||
#include "../include/utils/debug.hpp"
|
||||
#include "../include/modules/light.hpp"
|
||||
#include <dma.h>
|
||||
#include <draw.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <dma_tags.h>
|
||||
#include <gs_psm.h>
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
/** Initializes vars and creates data transfer packets
|
||||
* @param packetSize Size of data packet, should be increased when more data will be rendered
|
||||
*/
|
||||
GifSender::GifSender(u32 t_packetSize, ScreenSettings *t_screen) : screen(t_screen)
|
||||
{
|
||||
PRINT_LOG("Initializing GifSender");
|
||||
packetSize = t_packetSize;
|
||||
packets[0] = packet_init(t_packetSize, PACKET_NORMAL);
|
||||
packets[1] = packet_init(t_packetSize, PACKET_NORMAL);
|
||||
PRINT_LOG("GifSender initialized!");
|
||||
}
|
||||
|
||||
/** Releases packets memory */
|
||||
GifSender::~GifSender()
|
||||
{
|
||||
packet_free(packets[0]);
|
||||
packet_free(packets[1]);
|
||||
}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
#include <gif_tags.h>
|
||||
#include <gs_gp.h>
|
||||
|
||||
/** Send texture via GIF */
|
||||
void GifSender::sendTexture(Texture &texture, texbuffer_t *t_texBuffer)
|
||||
{
|
||||
const u16 packetSize = 40;
|
||||
packet_t *packet = packet_init(packetSize, PACKET_NORMAL);
|
||||
qword_t *q = packet->data;
|
||||
q = draw_texture_transfer(q, texture.data, texture.width, texture.height, GS_PSM_24, t_texBuffer->address, t_texBuffer->width);
|
||||
DMATAG_CNT(q, 2, 0, 0, 0);
|
||||
q++;
|
||||
q = draw_texture_wrapping(q, 0, &texture.wrapSettings);
|
||||
q = draw_texture_flush(q);
|
||||
dma_channel_send_chain(DMA_CHANNEL_GIF, packet->data, q - packet->data, 0, 0);
|
||||
dma_wait_fast();
|
||||
packet_free(packet);
|
||||
}
|
||||
|
||||
void GifSender::sendClear(zbuffer_t *t_zBuffer)
|
||||
{
|
||||
packet_t *packet = packet_init(100, PACKET_NORMAL);
|
||||
qword_t *q = packet->data;
|
||||
q++;
|
||||
q = draw_disable_tests(q, 0, t_zBuffer);
|
||||
q = draw_clear(q, 0,
|
||||
2048.0F - (screen->width / 2), 2048.0F - (screen->height / 2),
|
||||
screen->width, screen->height,
|
||||
0x10, 0x10, 0x10);
|
||||
q = draw_enable_tests(q, 0, t_zBuffer);
|
||||
q = draw_finish(q);
|
||||
DMATAG_END(packet->data, q - packet->data - 1, 0, 0, 0);
|
||||
dma_channel_send_chain(DMA_CHANNEL_GIF, packet->data, q - packet->data, 0, 0);
|
||||
dma_wait_fast();
|
||||
packet_free(packet);
|
||||
}
|
||||
|
||||
/** Used in game loop.
|
||||
* Switches current packet to next one
|
||||
*/
|
||||
void GifSender::initPacket(u8 t_context)
|
||||
{
|
||||
currentPacket = packets[t_context];
|
||||
if (currentPacket->qwords > (u32)packetSize || currentPacket->qwords < 0)
|
||||
PRINT_ERR("GifSender packet size error. Please consider to change packet size!\n");
|
||||
q = currentPacket->data;
|
||||
dmatag = q;
|
||||
q++;
|
||||
isAnyObjectAdded = 0;
|
||||
}
|
||||
|
||||
/** Sends packet to GIF. */
|
||||
void GifSender::sendPacket()
|
||||
{
|
||||
if (isAnyObjectAdded)
|
||||
{
|
||||
dmatag = q;
|
||||
q++;
|
||||
}
|
||||
q = draw_finish(q);
|
||||
DMATAG_END(dmatag, q - dmatag - 1, 0, 0, 0);
|
||||
dma_wait_fast();
|
||||
dma_channel_send_chain(DMA_CHANNEL_GIF, currentPacket->data, q - currentPacket->data, 0, 0);
|
||||
}
|
||||
|
||||
/** Adds clear screen to current packet */
|
||||
void GifSender::addClear(zbuffer_t *t_zBuffer)
|
||||
{
|
||||
q = draw_disable_tests(q, 0, t_zBuffer);
|
||||
q = draw_clear(q, 0,
|
||||
2048.0F - (screen->width / 2), 2048.0F - (screen->height / 2),
|
||||
screen->width, screen->height,
|
||||
0x10, 0x10, 0x10);
|
||||
q = draw_enable_tests(q, 0, t_zBuffer);
|
||||
}
|
||||
|
||||
/** Adds 3D objects to current packet
|
||||
* @param worldView Matrix
|
||||
* @param perspective Matrix with .setPerpsective() used [clone of gluPerspective]
|
||||
* @param objects3D Array of 3D objects pointers
|
||||
* @param amount Amount of 3D objects
|
||||
*/
|
||||
void GifSender::addObjects(RenderData *t_renderData, Mesh **t_objects3D, u32 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||
{
|
||||
if (!isAnyObjectAdded)
|
||||
{
|
||||
isAnyObjectAdded = true;
|
||||
DMATAG_CNT(dmatag, q - dmatag - 1, 0, 0, 0); // init tag (before first 3d obj)
|
||||
}
|
||||
qword_t *tempDMATag;
|
||||
tempDMATag = q;
|
||||
q++;
|
||||
|
||||
q = draw_texture_sampling(q, 0, &t_objects3D[0]->spec->lod);
|
||||
q = draw_texturebuffer(q, 0, &t_objects3D[0]->spec->textureBuffer, &t_objects3D[0]->spec->clut);
|
||||
dw = (u64 *)draw_prim_start(q, 0, t_renderData->prim, &t_objects3D[0]->color);
|
||||
|
||||
for (u32 i = 0; i < t_amount; i++)
|
||||
if (t_objects3D[i]->shouldBeFrustumCulled == 0 || t_objects3D[i]->isInFrustum(t_renderData->frustumPlanes))
|
||||
{
|
||||
u32 vertexCount = calc3DObject(*t_renderData->perspective, *t_objects3D[i], t_renderData, t_bulbs, t_bulbsCount);
|
||||
addCurrentCalcs(vertexCount);
|
||||
delete[] xyz;
|
||||
delete[] rgbaq;
|
||||
delete[] st;
|
||||
}
|
||||
|
||||
if ((u32)dw % 16) // if we are in the middle of qw, switch packet
|
||||
*dw++ = 0;
|
||||
|
||||
q = draw_prim_end((qword_t *)dw, 3, DRAW_STQ_REGLIST);
|
||||
|
||||
DMATAG_CNT(tempDMATag, q - tempDMATag - 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
/** Calculates 3D object data into xyz, rgbq, st
|
||||
* After it addCurrentSTQ() can be done
|
||||
* @param worldView Matrix
|
||||
* @param perspective Matrix with .setPerpsective() used [clone of gluPerspective]
|
||||
* @param mesh 3D object
|
||||
* @returns Vertex count
|
||||
*/
|
||||
u32 GifSender::calc3DObject(Matrix t_perspective, Mesh &t_mesh, RenderData *t_renderData, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||
{
|
||||
u32 vertexCount = t_mesh.getVertexCount();
|
||||
|
||||
VECTOR *vertices = new VECTOR[vertexCount];
|
||||
VECTOR *normals = new VECTOR[vertexCount];
|
||||
VECTOR *coordinates = new VECTOR[vertexCount];
|
||||
VECTOR *colors = new VECTOR[vertexCount];
|
||||
vertexCount = t_mesh.getDrawData(0, vertices, normals, coordinates, colors, *t_renderData->cameraPosition);
|
||||
|
||||
xyz = new xyz_t[vertexCount];
|
||||
rgbaq = new color_t[vertexCount];
|
||||
st = new texel_t[vertexCount];
|
||||
|
||||
VECTOR position, rotation;
|
||||
|
||||
vec3ToNative(position, t_mesh.position, 1.0F);
|
||||
vec3ToNative(rotation, t_mesh.rotation, 1.0F);
|
||||
|
||||
create_local_world(localWorld, position, rotation);
|
||||
|
||||
const u8 SHOULD_BE_LIGHTED = t_bulbs != NULL && t_mesh.shouldBeLighted;
|
||||
|
||||
if (SHOULD_BE_LIGHTED)
|
||||
create_local_light(localLight, rotation);
|
||||
|
||||
// I cant put perspective from renderData here. PS2SDK bug?
|
||||
create_local_screen(localScreen, localWorld, t_renderData->worldView->data, t_perspective.data);
|
||||
|
||||
if (SHOULD_BE_LIGHTED)
|
||||
{
|
||||
const u16 lightsCount = Light::getLightsCount(t_bulbsCount);
|
||||
VECTOR *lightDirections = new VECTOR[lightsCount];
|
||||
VECTOR *lightColors = new VECTOR[lightsCount];
|
||||
int *lightTypes = new int[lightsCount];
|
||||
|
||||
VECTOR *lights = new VECTOR[vertexCount];
|
||||
calculate_normals(normals, vertexCount, normals, localLight);
|
||||
|
||||
Light::calculateLight(lightDirections, lightColors, lightTypes, t_bulbs, t_bulbsCount, t_mesh.position);
|
||||
|
||||
calculate_lights(lights, vertexCount, normals, lightDirections, lightColors, lightTypes, lightsCount);
|
||||
|
||||
calculate_colours(colors, vertexCount, colors, lights);
|
||||
|
||||
delete[] lightDirections;
|
||||
delete[] lightColors;
|
||||
delete[] lightTypes;
|
||||
delete[] lights;
|
||||
}
|
||||
|
||||
calculate_vertices(vertices, vertexCount, vertices, localScreen);
|
||||
|
||||
convertCalcs(vertexCount, vertices, colors, coordinates, t_mesh.color.a);
|
||||
|
||||
delete[] vertices;
|
||||
delete[] normals;
|
||||
delete[] coordinates;
|
||||
delete[] colors;
|
||||
|
||||
return vertexCount;
|
||||
}
|
||||
|
||||
void GifSender::convertCalcs(u32 t_vertexCount, VECTOR *t_vertices, VECTOR *t_colors, VECTOR *t_sts, u8 t_alpha)
|
||||
{
|
||||
// TODO get this via screensettings
|
||||
const s32 centerX = ftoi4(2048);
|
||||
const s32 centerY = ftoi4(2048);
|
||||
const u32 maxZ = ftoi4(((float)0xFFFFFF) / 32.0F);
|
||||
float q = 1.00F;
|
||||
for (u32 i = 0; i < t_vertexCount; i++)
|
||||
{
|
||||
xyz[i].x = (u16)((t_vertices[i][0] + 1.0F) * centerX);
|
||||
xyz[i].y = (u16)((t_vertices[i][1] + 1.0F) * centerY);
|
||||
xyz[i].z = (u32)((t_vertices[i][2] + 1.0F) * maxZ);
|
||||
|
||||
if (t_vertices[i][3])
|
||||
q = 1 / t_vertices[i][3];
|
||||
|
||||
st[i].s = t_sts[i][0] * q;
|
||||
st[i].t = t_sts[i][1] * q;
|
||||
|
||||
rgbaq[i].r = (u8)(t_colors[i][0] * 128.0F);
|
||||
rgbaq[i].g = (u8)(t_colors[i][1] * 128.0F);
|
||||
rgbaq[i].b = (u8)(t_colors[i][2] * 128.0F);
|
||||
rgbaq[i].a = t_alpha;
|
||||
rgbaq[i].q = q;
|
||||
}
|
||||
}
|
||||
|
||||
/** Update q's double words. It may look strange, but this workaround
|
||||
* use's a 64-bit pointer to simplify adding data to the packet.
|
||||
*/
|
||||
void GifSender::addCurrentCalcs(u32 &t_vertexCount)
|
||||
{
|
||||
for (u32 i = 0; i < t_vertexCount; i++)
|
||||
{
|
||||
*dw++ = rgbaq[i].rgbaq;
|
||||
*dw++ = st[i].uv;
|
||||
*dw++ = xyz[i].xyz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/modules/light.hpp"
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
Light::Light() {}
|
||||
|
||||
Light::~Light() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
const u8 ADDITIONAL_LIGHTS = 1; // Ambient
|
||||
|
||||
u16 Light::getLightsCount(u32 t_bulbsCount) { return t_bulbsCount + ADDITIONAL_LIGHTS; }
|
||||
|
||||
/** Calculates lighting. Used in gifSender in object 3D calculations */
|
||||
void Light::calculateLight(VECTOR *t_lightDirections, VECTOR *t_lightColors, int *t_lightTypes, LightBulb *t_bulbs, u32 t_bulbsCount, Vector3 t_objPosition)
|
||||
{
|
||||
// --- Ambient light
|
||||
|
||||
t_lightTypes[0] = LIGHT_AMBIENT;
|
||||
|
||||
t_lightDirections[0][0] = 0.0F;
|
||||
t_lightDirections[0][1] = 0.0F;
|
||||
t_lightDirections[0][2] = 0.0F;
|
||||
t_lightDirections[0][3] = 1.0F;
|
||||
|
||||
t_lightColors[0][0] = 0.0F;
|
||||
t_lightColors[0][1] = 0.0F;
|
||||
t_lightColors[0][2] = 0.0F;
|
||||
t_lightColors[0][3] = 1.0F;
|
||||
|
||||
// ---
|
||||
|
||||
for (u8 i = 0; i < t_bulbsCount; i++)
|
||||
{
|
||||
t_lightTypes[i + 1] = LIGHT_DIRECTIONAL;
|
||||
|
||||
Vector3 newLight = Vector3(t_objPosition.x - t_bulbs[i].position.x,
|
||||
t_objPosition.y - t_bulbs[i].position.y,
|
||||
t_objPosition.z - t_bulbs[i].position.z);
|
||||
|
||||
newLight.normalize();
|
||||
newLight = newLight *
|
||||
(.1F +
|
||||
(t_bulbs[i].intensity / t_bulbs[i].position.distanceTo(t_objPosition)));
|
||||
|
||||
t_lightDirections[i + 1][0] = newLight.x;
|
||||
t_lightDirections[i + 1][1] = newLight.y;
|
||||
t_lightDirections[i + 1][2] = newLight.z;
|
||||
t_lightDirections[i + 1][3] = 1.0F;
|
||||
|
||||
t_lightColors[i + 1][0] = 0.8F;
|
||||
t_lightColors[i + 1][1] = 0.8F;
|
||||
t_lightColors[i + 1][2] = 0.8F;
|
||||
t_lightColors[i + 1][3] = 1.0F;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/modules/pad.hpp"
|
||||
|
||||
#include "../include/utils/debug.hpp"
|
||||
#include <kernel.h>
|
||||
#include <loadfile.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
/** Init vars, load modules, opens pad port and initializes pad */
|
||||
Pad::Pad()
|
||||
{
|
||||
this->oldPad = 0;
|
||||
this->loadModules();
|
||||
padInit(0);
|
||||
this->port = 0; // 0 -> Connector 1, 1 -> Connector 2
|
||||
this->slot = 0; // Always zero if not using multitap
|
||||
if ((this->ret = padPortOpen(this->port, this->slot, padBuf)) == 0)
|
||||
{
|
||||
PRINT_ERR("padPortOpen failed!");
|
||||
printf("padPortOpen returned: %d\n", this->ret);
|
||||
SleepThread();
|
||||
}
|
||||
if (!this->initPad())
|
||||
{
|
||||
PRINT_ERR("initPad failed!");
|
||||
SleepThread();
|
||||
}
|
||||
}
|
||||
|
||||
Pad::~Pad() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
/** Load SIO2MAN and PADMAN modules */
|
||||
void Pad::loadModules()
|
||||
{
|
||||
PRINT_LOG("Loading pad modules");
|
||||
this->ret = SifLoadModule("rom0:SIO2MAN", 0, NULL);
|
||||
if (this->ret < 0)
|
||||
{
|
||||
PRINT_ERR("SifLoadModule (SIO2MAN) failed!");
|
||||
printf("SifLoadModule returned: %d\n", this->ret);
|
||||
SleepThread();
|
||||
}
|
||||
this->ret = SifLoadModule("rom0:PADMAN", 0, NULL);
|
||||
if (this->ret < 0)
|
||||
{
|
||||
PRINT_ERR("SifLoadModule (PADMAN) failed!");
|
||||
printf("SifLoadModule returned: %d\n", this->ret);
|
||||
SleepThread();
|
||||
}
|
||||
PRINT_LOG("Pad modules loaded!");
|
||||
}
|
||||
|
||||
/** Wait when pad will be ready (stable and ready) */
|
||||
int Pad::waitPadReady()
|
||||
{
|
||||
int state;
|
||||
int lastState;
|
||||
char stateString[16];
|
||||
state = padGetState(this->port, this->slot);
|
||||
lastState = -1;
|
||||
while ((state != PAD_STATE_STABLE) && (state != PAD_STATE_FINDCTP1))
|
||||
{
|
||||
if (state != lastState)
|
||||
{
|
||||
padStateInt2String(state, stateString);
|
||||
PRINT_LOG("Pad state changed");
|
||||
printf("Curent pad(%d,%d) status: %s\n", this->port, this->slot, stateString);
|
||||
}
|
||||
lastState = state;
|
||||
state = padGetState(this->port, this->slot);
|
||||
}
|
||||
// Were the pad ever 'out of sync'?
|
||||
if (lastState != -1)
|
||||
PRINT_LOG("Pad is ready!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Initializes and checks type of pad */
|
||||
int Pad::initPad()
|
||||
{
|
||||
PRINT_LOG("Initializing pad");
|
||||
this->waitPadReady();
|
||||
// How many different modes can this device operate in?
|
||||
// i.e. get # entrys in the modetable
|
||||
int modes = padInfoMode(this->port, this->slot, PAD_MODETABLE, -1);
|
||||
if (modes == 0)
|
||||
{
|
||||
PRINT_ERR("Connected device is not a dual shock controller!"); // (it has no actuator engines)
|
||||
return 1;
|
||||
}
|
||||
// Verify that the controller has a DUAL SHOCK mode
|
||||
int i = 0;
|
||||
do
|
||||
{
|
||||
if (padInfoMode(this->port, this->slot, PAD_MODETABLE, i) == PAD_TYPE_DUALSHOCK)
|
||||
break;
|
||||
i++;
|
||||
} while (i < modes);
|
||||
|
||||
if (i >= modes)
|
||||
{
|
||||
PRINT_ERR("Connected device is not a dual shock controller!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If ExId != 0x0 => This controller has actuator engines
|
||||
// This check should always pass if the Dual Shock test above passed
|
||||
this->ret = padInfoMode(this->port, this->slot, PAD_MODECUREXID, 0);
|
||||
if (this->ret == 0)
|
||||
{
|
||||
PRINT_ERR("Connected device is not a dual shock controller!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
PRINT_LOG("Enabling dual shock functions.");
|
||||
|
||||
// When using MMODE_LOCK, user cant change mode with Select button
|
||||
padSetMainMode(this->port, this->slot, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK);
|
||||
|
||||
this->waitPadReady();
|
||||
printf("Pad has pressure sensitive buttons? %d\n", padInfoPressMode(this->port, this->slot));
|
||||
this->waitPadReady();
|
||||
padEnterPressMode(this->port, this->slot); // Set pressure sensitive mode
|
||||
this->waitPadReady();
|
||||
this->actuators = padInfoAct(this->port, this->slot, -1, 0);
|
||||
printf("# of actuators: %d\n", this->actuators);
|
||||
if (actuators != 0)
|
||||
{
|
||||
this->actAlign[0] = 0; // Enable small engine
|
||||
this->actAlign[1] = 1; // Enable big engine
|
||||
this->actAlign[2] = 0xff;
|
||||
this->actAlign[3] = 0xff;
|
||||
this->actAlign[4] = 0xff;
|
||||
this->actAlign[5] = 0xff;
|
||||
this->waitPadReady();
|
||||
printf("padSetActAlign: %d\n", padSetActAlign(this->port, this->slot, actAlign));
|
||||
}
|
||||
else
|
||||
printf("Did not find any actuators.\n");
|
||||
this->waitPadReady();
|
||||
PRINT_LOG("Pad initialized!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Updates state of joys/buttons */
|
||||
void Pad::update()
|
||||
{
|
||||
int x = 0;
|
||||
this->ret = padGetState(this->port, this->slot);
|
||||
while ((this->ret != PAD_STATE_STABLE) && (this->ret != PAD_STATE_FINDCTP1))
|
||||
{
|
||||
if (this->ret == PAD_STATE_DISCONN)
|
||||
printf("Pad(%d, %d) is disconnected\n", this->port, this->slot);
|
||||
this->ret = padGetState(this->port, this->slot);
|
||||
}
|
||||
if (x == 1)
|
||||
printf("Pad: OK!\n");
|
||||
|
||||
this->ret = padRead(this->port, this->slot, &this->buttons); // this->port, this->slot, this->buttons
|
||||
|
||||
if (this->ret != 0)
|
||||
{
|
||||
this->padData = 0xffff ^ this->buttons.btns;
|
||||
|
||||
this->newPad = this->padData & ~this->oldPad;
|
||||
this->oldPad = this->padData;
|
||||
this->reset();
|
||||
this->rJoyH = this->buttons.rjoy_h;
|
||||
this->rJoyV = this->buttons.rjoy_v;
|
||||
this->lJoyH = this->buttons.ljoy_h;
|
||||
this->lJoyV = this->buttons.ljoy_v;
|
||||
|
||||
if (this->newPad & PAD_CROSS)
|
||||
this->isCrossClicked = 1;
|
||||
if (this->newPad & PAD_SQUARE)
|
||||
this->isSquareClicked = 1;
|
||||
if (this->newPad & PAD_TRIANGLE)
|
||||
this->isTriangleClicked = 1;
|
||||
if (this->newPad & PAD_CIRCLE)
|
||||
this->isCircleClicked = 1;
|
||||
|
||||
if (this->buttons.up_p > 0)
|
||||
this->isDpadUpPressed = 1;
|
||||
if (this->buttons.down_p > 0)
|
||||
this->isDpadDownPressed = 1;
|
||||
if (this->buttons.left_p)
|
||||
this->isDpadLeftPressed = 1;
|
||||
if (this->buttons.right_p)
|
||||
this->isDpadRightPressed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Resets state of joys/buttons */
|
||||
void Pad::reset()
|
||||
{
|
||||
this->isCrossClicked = 0;
|
||||
this->isSquareClicked = 0;
|
||||
this->isTriangleClicked = 0;
|
||||
this->isCircleClicked = 0;
|
||||
this->isDpadUpPressed = 0;
|
||||
this->isDpadDownPressed = 0;
|
||||
this->isDpadLeftPressed = 0;
|
||||
this->isDpadRightPressed = 0;
|
||||
this->lJoyH = 0;
|
||||
this->lJoyV = 0;
|
||||
this->rJoyH = 0;
|
||||
this->rJoyV = 0;
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/modules/renderer.hpp"
|
||||
|
||||
#include <dma.h>
|
||||
#include <graph.h>
|
||||
#include <packet.h>
|
||||
#include <draw.h>
|
||||
#include <gs_psm.h>
|
||||
#include "../include/utils/debug.hpp"
|
||||
#include "../include/utils/math.hpp"
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
/** Initialize DMA<->GIF channel
|
||||
* Allocate buffers
|
||||
* Initialize screen
|
||||
* Initialize drawing environment
|
||||
* Load/setup textures
|
||||
* @param screenW Half of screen width
|
||||
* @param screenH Half of screen height
|
||||
*/
|
||||
Renderer::Renderer(u32 t_packetSize, ScreenSettings *t_screen)
|
||||
{
|
||||
PRINT_LOG("Initializing renderer");
|
||||
dma_channel_initialize(DMA_CHANNEL_GIF, NULL, 0); // Initialize DMA to enable data transfer
|
||||
dma_channel_fast_waits(DMA_CHANNEL_GIF);
|
||||
context = 0;
|
||||
lastTextureId = 0;
|
||||
isFrameEmpty = false;
|
||||
flipPacket = packet_init(3, PACKET_UCAB); // Uncached accelerated
|
||||
allocateBuffers(t_screen->width, t_screen->height);
|
||||
initDrawingEnv(t_screen->width, t_screen->height);
|
||||
setPrim();
|
||||
gifSender = new GifSender(t_packetSize, t_screen);
|
||||
vifSender = new VifSender();
|
||||
perspective.setPerspective(*t_screen);
|
||||
renderData.perspective = &perspective;
|
||||
PRINT_LOG("Renderer initialized!");
|
||||
}
|
||||
|
||||
Renderer::~Renderer() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
/** Initializes drawing environment (1st app packet) */
|
||||
void Renderer::initDrawingEnv(float t_screenW, float t_screenH)
|
||||
{
|
||||
PRINT_LOG("Initializing drawing environment");
|
||||
packet_t *packet = packet_init(20, PACKET_NORMAL);
|
||||
u16 halfW = (u16)t_screenW / 2;
|
||||
u16 halfH = (u16)t_screenH / 2;
|
||||
qword_t *q = packet->data; // Generic qword pointer.
|
||||
q = draw_setup_environment(q, 0, frameBuffers, &(zBuffer));
|
||||
q = draw_primitive_xyoffset(q, 0, (2048 - halfW), (2048 - halfH));
|
||||
q = draw_finish(q);
|
||||
// Now send the packet, no need to wait since it's the first.
|
||||
dma_channel_send_normal(DMA_CHANNEL_GIF, packet->data, q - packet->data, 0, 0);
|
||||
dma_wait_fast();
|
||||
packet_free(packet);
|
||||
PRINT_LOG("Drawing environment initialized!");
|
||||
}
|
||||
|
||||
/** Sets drawing prim for all 3D objects */
|
||||
void Renderer::setPrim()
|
||||
{
|
||||
prim.type = PRIM_TRIANGLE;
|
||||
prim.shading = PRIM_SHADE_FLAT;
|
||||
prim.mapping = DRAW_ENABLE;
|
||||
prim.fogging = DRAW_DISABLE;
|
||||
prim.blending = DRAW_ENABLE;
|
||||
prim.antialiasing = DRAW_DISABLE;
|
||||
prim.mapping_type = PRIM_MAP_ST;
|
||||
prim.colorfix = PRIM_UNFIXED;
|
||||
renderData.prim = &prim;
|
||||
PRINT_LOG("Prim set!");
|
||||
}
|
||||
|
||||
void Renderer::changeTexture(Mesh *t_mesh, u8 t_textureIndex)
|
||||
{
|
||||
if (t_mesh->spec->textures[t_textureIndex].id != lastTextureId)
|
||||
{
|
||||
lastTextureId = t_mesh->spec->textures[t_textureIndex].id;
|
||||
t_mesh->spec->deallocateTextureBuffer();
|
||||
t_mesh->spec->allocateTextureBuffer(t_mesh->spec->textures[t_textureIndex].width, t_mesh->spec->textures[t_textureIndex].height);
|
||||
GifSender::sendTexture(t_mesh->spec->textures[t_textureIndex], &t_mesh->spec->textureBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/** Defines and allocates framebuffers and zbuffer */
|
||||
void Renderer::allocateBuffers(float t_screenW, float t_screenH)
|
||||
{
|
||||
frameBuffers[0].width = (u16)t_screenW;
|
||||
frameBuffers[0].height = (u16)t_screenH;
|
||||
frameBuffers[0].mask = 0;
|
||||
frameBuffers[0].psm = GS_PSM_32;
|
||||
frameBuffers[0].address = graph_vram_allocate((u16)t_screenW, (u16)t_screenH, frameBuffers[0].psm, GRAPH_ALIGN_PAGE);
|
||||
|
||||
frameBuffers[1].width = (u16)t_screenW;
|
||||
frameBuffers[1].height = (u16)t_screenH;
|
||||
frameBuffers[1].mask = 0;
|
||||
frameBuffers[1].psm = GS_PSM_32;
|
||||
frameBuffers[1].address = graph_vram_allocate((u16)t_screenW, (u16)t_screenH, frameBuffers[1].psm, GRAPH_ALIGN_PAGE);
|
||||
|
||||
zBuffer.enable = DRAW_ENABLE;
|
||||
zBuffer.mask = 0;
|
||||
zBuffer.method = ZTEST_METHOD_GREATER_EQUAL;
|
||||
zBuffer.zsm = GS_ZBUF_32;
|
||||
zBuffer.address = graph_vram_allocate((u16)t_screenW, (u16)t_screenH, zBuffer.zsm, GRAPH_ALIGN_PAGE);
|
||||
PRINT_LOG("Framebuffers, zBuffer set and allocated!");
|
||||
|
||||
// Initialize the screen and tie the first framebuffer to the read circuits.
|
||||
graph_initialize(frameBuffers[1].address, frameBuffers[1].width, frameBuffers[1].height, frameBuffers[1].psm, 0, 0);
|
||||
}
|
||||
|
||||
/// --- Draw: PATH3
|
||||
|
||||
/** PATH3 Many + lighting */
|
||||
void Renderer::drawByPath3(Mesh **t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||
{
|
||||
beginFrameIfNeeded();
|
||||
gifSender->initPacket(context);
|
||||
// TODO
|
||||
changeTexture(t_meshes[0], 0);
|
||||
gifSender->addObjects(&renderData, t_meshes, t_amount, t_bulbs, t_bulbsCount);
|
||||
gifSender->sendPacket();
|
||||
draw_wait_finish();
|
||||
}
|
||||
|
||||
/** PATH3 Single + lighting */
|
||||
void Renderer::drawByPath3(Mesh *t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||
{
|
||||
beginFrameIfNeeded();
|
||||
gifSender->initPacket(context);
|
||||
// TODO
|
||||
changeTexture(t_mesh, 0);
|
||||
gifSender->addObjects(&renderData, &t_mesh, 1, t_bulbs, t_bulbsCount);
|
||||
gifSender->sendPacket();
|
||||
draw_wait_finish();
|
||||
}
|
||||
|
||||
/** PATH3 Many */
|
||||
void Renderer::drawByPath3(Mesh **t_meshes, u16 t_amount) { drawByPath3(t_meshes, t_amount, NULL, 0); }
|
||||
|
||||
/** PATH3 Single */
|
||||
void Renderer::drawByPath3(Mesh *t_mesh) { drawByPath3(t_mesh, NULL, 0); }
|
||||
|
||||
/// --- Draw: PATH1
|
||||
|
||||
/** PATH1 Many + lighting */
|
||||
void Renderer::draw(Mesh **t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||
{
|
||||
// TODO
|
||||
beginFrameIfNeeded();
|
||||
for (u16 i = 0; i < t_amount; i++)
|
||||
draw(t_meshes[i], t_bulbs, t_bulbsCount);
|
||||
}
|
||||
|
||||
/** PATH1 Single + lighting */
|
||||
void Renderer::draw(Mesh *t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||
{
|
||||
beginFrameIfNeeded();
|
||||
// TODO VU1 send single list here
|
||||
if (!t_mesh->isObjLoaded && !t_mesh->isDffLoaded && !t_mesh->isMd2Loaded)
|
||||
return;
|
||||
u32 vertCount = t_mesh->getVertexCount();
|
||||
VECTOR *vertices = new VECTOR[vertCount];
|
||||
VECTOR *normals = new VECTOR[vertCount];
|
||||
VECTOR *coordinates = new VECTOR[vertCount];
|
||||
VECTOR *colors = new VECTOR[vertCount];
|
||||
if (t_mesh->isObjLoaded || t_mesh->isMd2Loaded)
|
||||
{
|
||||
changeTexture(t_mesh, 0);
|
||||
vertCount = t_mesh->getDrawData(0, vertices, normals, coordinates, colors, *renderData.cameraPosition);
|
||||
vifSender->drawMesh(&renderData, perspective, vertCount, vertices, normals, coordinates, colors, t_mesh, t_bulbs, t_bulbsCount);
|
||||
}
|
||||
else if (t_mesh->isDffLoaded)
|
||||
for (u32 i = 0; i < t_mesh->dff->clump.geometryList.geometries[0].extension.materialSplit.header.splitCount; i++)
|
||||
{
|
||||
const u32 currentTexI = t_mesh->dff->clump.geometryList.geometries[0].extension.materialSplit.splitInformation[i].materialIndex;
|
||||
changeTexture(t_mesh, currentTexI);
|
||||
vertCount = t_mesh->getDrawData(i, vertices, normals, coordinates, colors, *renderData.cameraPosition);
|
||||
vifSender->drawMesh(&renderData, perspective, vertCount, vertices, normals, coordinates, colors, t_mesh, t_bulbs, t_bulbsCount);
|
||||
}
|
||||
delete[] vertices;
|
||||
delete[] normals;
|
||||
delete[] coordinates;
|
||||
delete[] colors;
|
||||
}
|
||||
|
||||
/** PATH1 Many */
|
||||
void Renderer::draw(Mesh **t_objects3D, u16 t_amount) { draw(t_objects3D, t_amount, NULL, 0); }
|
||||
|
||||
/** PATH1 Single */
|
||||
void Renderer::draw(Mesh *t_mesh) { draw(t_mesh, NULL, 0); }
|
||||
|
||||
/// ---
|
||||
|
||||
void Renderer::setCameraDefinitions(Matrix *t_worldView, Vector3 *t_cameraPos, Plane *t_planes)
|
||||
{
|
||||
renderData.worldView = t_worldView;
|
||||
renderData.cameraPosition = t_cameraPos;
|
||||
renderData.frustumPlanes = t_planes;
|
||||
}
|
||||
|
||||
void Renderer::beginFrameIfNeeded()
|
||||
{
|
||||
if (isFrameEmpty)
|
||||
{
|
||||
isFrameEmpty = false;
|
||||
gifSender->sendClear(&zBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::endFrame(float fps)
|
||||
{
|
||||
if (!isFrameEmpty)
|
||||
{
|
||||
if (fps > 49.0F)
|
||||
graph_wait_vsync();
|
||||
flipBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
/** We need to flip buffers outside of the chain, for some reason,
|
||||
* so we use a separate small packet
|
||||
* Do not use this method. This is called via packetManager
|
||||
*/
|
||||
void Renderer::flipBuffers()
|
||||
{
|
||||
graph_set_framebuffer_filtered(
|
||||
frameBuffers[context].address,
|
||||
frameBuffers[context].width,
|
||||
frameBuffers[context].psm,
|
||||
0,
|
||||
0);
|
||||
context ^= 1;
|
||||
isFrameEmpty = 1;
|
||||
qword_t *q = flipPacket->data;
|
||||
q = draw_framebuffer(q, 0, &frameBuffers[context]);
|
||||
q = draw_finish(q);
|
||||
dma_wait_fast();
|
||||
dma_channel_send_normal_ucab(DMA_CHANNEL_GIF, flipPacket->data, q - flipPacket->data, 0);
|
||||
draw_wait_finish();
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/modules/timer.hpp"
|
||||
|
||||
#include <timer.h>
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
Timer::Timer()
|
||||
{
|
||||
this->lastTime = *T3_COUNT;
|
||||
}
|
||||
|
||||
Timer::~Timer() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
u32 Timer::getTimeDelta()
|
||||
{
|
||||
this->time = *T3_COUNT;
|
||||
|
||||
if (this->time < this->lastTime) // The counter has wrapped
|
||||
this->change = this->time + (65536 - this->lastTime);
|
||||
else
|
||||
this->change = this->time - this->lastTime;
|
||||
|
||||
this->lastTime = this->time;
|
||||
return this->change;
|
||||
}
|
||||
|
||||
void Timer::primeTimer()
|
||||
{
|
||||
lastTime = *T3_COUNT;
|
||||
}
|
||||
|
||||
float Timer::getFPS()
|
||||
{
|
||||
u32 timeDelta = this->getTimeDelta();
|
||||
|
||||
if (timeDelta == 0)
|
||||
return -1.0F;
|
||||
|
||||
return 15625.0F / (float)timeDelta; // PAL
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/modules/vif_sender.hpp"
|
||||
|
||||
#include <gs_gp.h>
|
||||
#include <dma.h>
|
||||
#include <gif_tags.h>
|
||||
#include "../include/utils/math.hpp"
|
||||
#include "../include/utils/debug.hpp"
|
||||
|
||||
// Similiar set is in PS2SDK, but for VU1 we have to switch ST with RGBAQ, because VU1 must know Q before sending RGBAQ
|
||||
#define DRAW_R_STQ_REGLIST ((u64)GIF_REG_ST) << 0 | ((u64)GIF_REG_RGBAQ) << 4 | ((u64)GIF_REG_XYZ2) << 8
|
||||
const u32 VU1_PACKAGE_VERTS_PER_BUFF = 96; // Remember to modify buffer size in vu1 also
|
||||
const u32 VU1_PACKAGES_PER_PACKET = 6;
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
VifSender::VifSender()
|
||||
{
|
||||
PRINT_LOG("Initializing VifSender");
|
||||
PRINT_LOG("VifSender initialized!");
|
||||
}
|
||||
|
||||
VifSender::~VifSender() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// ----
|
||||
|
||||
void VifSender::drawMesh(RenderData *t_renderData, Matrix t_perspective, u32 vertCount2, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, VECTOR *colors, Mesh *t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||
{
|
||||
if (t_mesh->shouldBeFrustumCulled == 1 && !t_mesh->isInFrustum(t_renderData->frustumPlanes))
|
||||
return;
|
||||
|
||||
vec3ToNative(position, t_mesh->position, 1.0F);
|
||||
vec3ToNative(rotation, t_mesh->rotation, 1.0F);
|
||||
create_local_world(localWorld, position, rotation);
|
||||
create_local_screen(localScreen, localWorld, t_renderData->worldView->data, t_perspective.data);
|
||||
|
||||
// TODO Send it once man xd
|
||||
vu1.sendSingleRefList(0, &localScreen, 4);
|
||||
|
||||
// we have to split 3D object into small parts, because of small memory of VU1
|
||||
for (u32 i = 0; i < vertCount2;)
|
||||
{
|
||||
vu1.createList();
|
||||
for (u8 j = 0; j < VU1_PACKAGES_PER_PACKET; j++) // how many "packages" per one packet
|
||||
{
|
||||
if (i != 0) // we have to go back to avoid the visual artifacts
|
||||
i -= 3;
|
||||
|
||||
const u32 endI = i + (VU1_PACKAGE_VERTS_PER_BUFF - 1) > vertCount2 ? vertCount2 : i + (VU1_PACKAGE_VERTS_PER_BUFF - 1);
|
||||
drawVertices(t_mesh, i, endI, vertices, colors, coordinates, t_renderData->prim);
|
||||
if (endI == vertCount2) // if there are no more vertices to draw, break
|
||||
{
|
||||
i = vertCount2;
|
||||
break;
|
||||
}
|
||||
i += (VU1_PACKAGE_VERTS_PER_BUFF - 1);
|
||||
i++;
|
||||
}
|
||||
vu1.sendList();
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw using PATH1 */
|
||||
void VifSender::drawVertices(Mesh *t_mesh, u32 t_start, u32 t_end, VECTOR *t_vertices, VECTOR *t_colors, VECTOR *t_coordinates, prim_t *t_prim)
|
||||
{
|
||||
const u32 vertCount = t_end - t_start;
|
||||
vu1.addListBeginning();
|
||||
|
||||
// TODO get this via screensettings
|
||||
vu1.addFloat(2048.0F); // scale
|
||||
vu1.addFloat(2048.0F); // scale
|
||||
vu1.addFloat(((float)0xFFFFFF) / 32.0F); // scale
|
||||
vu1.add32(vertCount); // vertex count
|
||||
|
||||
vu1.add128(GIF_SET_TAG(1, 0, 0, 0, GIF_FLG_PACKED, 1), GIF_REG_AD); // 1x set tag
|
||||
|
||||
vu1.add128( // tex -> lod
|
||||
GS_SET_TEX1(
|
||||
t_mesh->spec->lod.calculation,
|
||||
t_mesh->spec->lod.max_level,
|
||||
t_mesh->spec->lod.mag_filter,
|
||||
t_mesh->spec->lod.min_filter,
|
||||
t_mesh->spec->lod.mipmap_select,
|
||||
t_mesh->spec->lod.l,
|
||||
(int)(t_mesh->spec->lod.k * 16.0F)),
|
||||
GS_REG_TEX1);
|
||||
|
||||
vu1.add128( // tex -> buff + clut
|
||||
GS_SET_TEX0(
|
||||
t_mesh->spec->textureBuffer.address >> 6,
|
||||
t_mesh->spec->textureBuffer.width >> 6,
|
||||
t_mesh->spec->textureBuffer.psm,
|
||||
t_mesh->spec->textureBuffer.info.width,
|
||||
t_mesh->spec->textureBuffer.info.height,
|
||||
t_mesh->spec->textureBuffer.info.components,
|
||||
t_mesh->spec->textureBuffer.info.function,
|
||||
t_mesh->spec->clut.address >> 6,
|
||||
t_mesh->spec->clut.psm,
|
||||
t_mesh->spec->clut.storage_mode,
|
||||
t_mesh->spec->clut.start,
|
||||
t_mesh->spec->clut.load_method),
|
||||
GS_REG_TEX0);
|
||||
|
||||
vu1.add128(
|
||||
GS_GIFTAG(
|
||||
vertCount, // amount of loops
|
||||
1,
|
||||
1,
|
||||
GS_PRIM(
|
||||
t_prim->type,
|
||||
t_prim->shading,
|
||||
t_prim->mapping,
|
||||
t_prim->fogging,
|
||||
t_prim->blending,
|
||||
t_prim->antialiasing,
|
||||
t_prim->mapping_type,
|
||||
0, // context
|
||||
t_prim->colorfix),
|
||||
GS_GIFTAG_PACKED,
|
||||
3), // STQ + RGBA + XYZ
|
||||
DRAW_R_STQ_REGLIST);
|
||||
|
||||
for (u8 j = 0; j < 4; j++)
|
||||
vu1.add32(128);
|
||||
|
||||
//// Clipping tests start
|
||||
|
||||
// const float minZ = 1;
|
||||
// const float maxZ = 65535;
|
||||
// const int iGuardDimXY = 2048;
|
||||
|
||||
// vu1.addFloat(1.0F); // TODO clipping maybe there is problem?
|
||||
// vu1.addFloat(1.0F);
|
||||
// vu1.addFloat(1.0F);
|
||||
// vu1.addFloat(1.0F);
|
||||
// float xClip = (float)2048.0f/(drawContext.GetFBWidth() * 0.5f * 2.0f);
|
||||
// packet += Math::Max( xClip, 1.0f );
|
||||
// float yClip = (float)2048.0f/(drawContext.GetFBHeight() * 0.5f * 2.0f);
|
||||
// packet += Math::Max( yClip, 1.0f );
|
||||
// float depthClip = 2048.0f / depthClipToGs;
|
||||
// // FIXME: maybe these 2048's should be 2047.5s...
|
||||
// depthClip *= 1.003f; // round up a bit for fp error (????)
|
||||
// packet += depthClip;
|
||||
// // enable/disable clipping
|
||||
// packet += (drawContext.GetDoClipping()) ? 1 : 0;
|
||||
|
||||
u32 depthBits = 24; // or 28(fog) or 16
|
||||
float depthClipToGs = (float)((1 << depthBits) - 1) / 2.0f;
|
||||
vu1.addFloat(2048.0f / (640.0F * 0.5f * 2.0f));
|
||||
vu1.addFloat(2048.0f / (480.0F * 0.5f * 2.0f));
|
||||
vu1.addFloat((2048.0f / depthClipToGs) * 1.003F);
|
||||
// vu1.addFloat(2048.0F); // scale
|
||||
// vu1.addFloat(2048.0F); // scale
|
||||
// vu1.addFloat(((float)0xFFFFFF) / 32.0F); // scale
|
||||
vu1.addFloat(0.0F);
|
||||
// vu1.addFloat(0.5f * iGuardDimXY);
|
||||
// vu1.addFloat(-0.5f * iGuardDimXY);
|
||||
// vu1.addFloat(1.0F);
|
||||
// vu1.addFloat(500.0F); // far
|
||||
|
||||
//// Clipping tests end
|
||||
|
||||
vu1.addListEnding();
|
||||
vu1.addReferenceList(0, t_vertices + t_start, 2 * vertCount, 1);
|
||||
vu1.addReferenceList(0, t_coordinates + t_start, 2 * vertCount, 1);
|
||||
vu1.addStartProgram();
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/modules/vu1.hpp"
|
||||
|
||||
#include "../include/utils/debug.hpp"
|
||||
#include <dma.h>
|
||||
#include <string.h>
|
||||
#include <kernel.h>
|
||||
|
||||
// ----
|
||||
// Constructors/Destructors
|
||||
// ----
|
||||
|
||||
VU1::VU1()
|
||||
{
|
||||
PRINT_LOG("Initializing VU1");
|
||||
currentBuffer = 0;
|
||||
switchBuffer = 0;
|
||||
PRINT_LOG("VU1 initialized!");
|
||||
}
|
||||
|
||||
VU1::~VU1() {}
|
||||
|
||||
// ----
|
||||
// Methods
|
||||
// -
|
||||
|
||||
/** Create dynamic list */
|
||||
void VU1::createList()
|
||||
{
|
||||
switchBuffer = !switchBuffer;
|
||||
memset((char *)&buildList, 0, sizeof(buildList));
|
||||
|
||||
if (switchBuffer)
|
||||
currentBuffer = (char *)&dmaBuffer1;
|
||||
else
|
||||
currentBuffer = (char *)&dmaBuffer2;
|
||||
buildList.kickBuffer = currentBuffer;
|
||||
}
|
||||
|
||||
/** Add reference list and send via VIF1
|
||||
* Not using TOPS register
|
||||
* Similar to addReferenceList()
|
||||
*/
|
||||
void VU1::sendSingleRefList(int t_destAddress, void *t_data, int t_quadSize)
|
||||
{
|
||||
checkDataAlignment(t_data);
|
||||
|
||||
u8 tempBuffer[32] __attribute__((aligned(16)));
|
||||
void *chain = (u64 *)&tempBuffer; // uncached
|
||||
|
||||
*((u64 *)chain)++ = DMA_REF_TAG((u32)t_data, t_quadSize);
|
||||
*((u32 *)chain)++ = VIF_CODE(VIF_STCYL, 0, 0x0101);
|
||||
*((u32 *)chain)++ = VIF_CODE(VIF_UNPACK_V4_32, t_quadSize, t_destAddress);
|
||||
|
||||
*((u64 *)chain)++ = DMA_END_TAG(0);
|
||||
*((u32 *)chain)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||
*((u32 *)chain)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||
|
||||
FlushCache(0);
|
||||
dma_channel_send_chain(DMA_CHANNEL_VIF1, tempBuffer, 0, DMA_FLAG_TRANSFERTAG, 0);
|
||||
dma_channel_wait(DMA_CHANNEL_VIF1, VU1_DMA_CHAN_TIMEOUT);
|
||||
}
|
||||
|
||||
/** Add list beginning, set's double buffer if not set */
|
||||
void VU1::addListBeginning()
|
||||
{
|
||||
if (buildList.isBuilding == 1)
|
||||
PRINT_ERR("Please end current list list before adding new one!");
|
||||
|
||||
if (isDoubleBufferSet == 0)
|
||||
addDoubleBufferSetting();
|
||||
else
|
||||
addFlush();
|
||||
|
||||
buildList.dmaSizeAll += buildList.dmaSize;
|
||||
buildList.dmaSize = 0;
|
||||
buildList.offset = currentBuffer;
|
||||
*((u64 *)currentBuffer)++ = DMA_CNT_TAG(0); // placeholder
|
||||
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_STCYL, 0, 0x0101); // placeholder
|
||||
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_UNPACK_V4_32, 0, 0); // placeholder
|
||||
buildList.isBuilding = 1;
|
||||
}
|
||||
|
||||
/** Add list ending and fix unpack size */
|
||||
void VU1::addListEnding()
|
||||
{
|
||||
if (buildList.isBuilding == 0)
|
||||
{
|
||||
PRINT_ERR("Please add list beginning first. Nothing to end!");
|
||||
return;
|
||||
}
|
||||
|
||||
while ((buildList.dmaSize & 0xF))
|
||||
{
|
||||
*((u32 *)currentBuffer)++ = 0;
|
||||
buildList.dmaSize += 4;
|
||||
}
|
||||
|
||||
*((u64 *)buildList.offset)++ = DMA_CNT_TAG(buildList.dmaSize >> 4);
|
||||
*((u32 *)buildList.offset)++ = VIF_CODE(VIF_STCYL, 0, 0x0101);
|
||||
*((u32 *)buildList.offset)++ = AddUnpack(V4_32, 0, buildList.dmaSize >> 4, 1);
|
||||
|
||||
buildList.isBuilding = 0;
|
||||
}
|
||||
|
||||
/** Add list which will load data from given pointer
|
||||
* A lot faster than standard list.
|
||||
* @param offset offset before data in quadwords
|
||||
* @param data data pointer
|
||||
* @param size in quadwords
|
||||
* @param useTops when true, data will be loaded at the beginning of buffer (BASE+OFFSET)
|
||||
*/
|
||||
void VU1::addReferenceList(u32 t_offset, void *t_data, u32 t_size, u8 t_useTops)
|
||||
{
|
||||
checkDataAlignment(t_data);
|
||||
if (buildList.isBuilding == 1)
|
||||
PRINT_ERR("Please end current list list before adding new one!");
|
||||
*((u64 *)currentBuffer)++ = DMA_REF_TAG((u32)t_data, t_size);
|
||||
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_STCYL, 0, 0x0101);
|
||||
*((u32 *)currentBuffer)++ =
|
||||
AddUnpack(V4_32, t_useTops == 1 ? buildList.dmaSize / 16 : t_offset / 16, t_size, t_useTops);
|
||||
buildList.dmaSize += t_size * 8;
|
||||
buildList.dmaSizeAll += buildList.dmaSize;
|
||||
}
|
||||
|
||||
/** Start VU1 program */
|
||||
void VU1::addStartProgram()
|
||||
{
|
||||
*((u64 *)currentBuffer)++ = DMA_CNT_TAG(8 >> 4);
|
||||
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_MSCAL, 0, 0);
|
||||
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_FLUSH, 0, 0);
|
||||
;
|
||||
}
|
||||
|
||||
/** Continue VU1 program from "--cont" line */
|
||||
void VU1::addContinueProgram()
|
||||
{
|
||||
*((u64 *)currentBuffer)++ = DMA_CNT_TAG(8 >> 4);
|
||||
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_MSCAL, 0, 0);
|
||||
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_FLUSH, 0, 0);
|
||||
;
|
||||
}
|
||||
|
||||
/** Add end tag and send packet via VIF1 */
|
||||
void VU1::sendList()
|
||||
{
|
||||
*((u64 *)currentBuffer)++ = DMA_END_TAG(0);
|
||||
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||
dma_channel_wait(DMA_CHANNEL_VIF1, VU1_DMA_CHAN_TIMEOUT);
|
||||
dma_channel_send_chain(DMA_CHANNEL_VIF1, buildList.kickBuffer, (u32 *)currentBuffer - (u32 *)buildList.kickBuffer, DMA_FLAG_TRANSFERTAG, 0);
|
||||
}
|
||||
|
||||
void VU1::addDoubleBufferSetting()
|
||||
{
|
||||
*((u64 *)currentBuffer)++ = DMA_CNT_TAG(8 >> 4);
|
||||
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_BASE, 0, 8);
|
||||
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_OFFSET, 0, 496);
|
||||
isDoubleBufferSet = 1;
|
||||
}
|
||||
|
||||
void VU1::addFlush()
|
||||
{
|
||||
*((u64 *)currentBuffer)++ = DMA_CNT_TAG(8 >> 4);
|
||||
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_FLUSH, 0, 0);
|
||||
}
|
||||
|
||||
void VU1::checkDataAlignment(void *t_data)
|
||||
{
|
||||
if (((u32)t_data & 0xF))
|
||||
PRINT_ERR("data is not 16 byte aligned!");
|
||||
}
|
||||
|
||||
// ----
|
||||
// List adding
|
||||
// ----
|
||||
|
||||
void VU1::add128(u64 v1, u64 v2)
|
||||
{
|
||||
checkList();
|
||||
*((u64 *)currentBuffer)++ = v1;
|
||||
*((u64 *)currentBuffer)++ = v2;
|
||||
buildList.dmaSize += 16;
|
||||
}
|
||||
|
||||
void VU1::add64(u64 v)
|
||||
{
|
||||
checkList();
|
||||
*((u64 *)currentBuffer)++ = v;
|
||||
buildList.dmaSize += 8;
|
||||
}
|
||||
|
||||
void VU1::add32(u32 v)
|
||||
{
|
||||
checkList();
|
||||
*((u32 *)currentBuffer)++ = v;
|
||||
buildList.dmaSize += 4;
|
||||
}
|
||||
|
||||
void VU1::addFloat(float v)
|
||||
{
|
||||
checkList();
|
||||
*((float *)currentBuffer)++ = v;
|
||||
buildList.dmaSize += 4;
|
||||
}
|
||||
|
||||
void VU1::checkList()
|
||||
{
|
||||
if (buildList.isBuilding == 0)
|
||||
PRINT_ERR("Please add list beginning before adding data!");
|
||||
if (buildList.dmaSizeAll > VIF_BUFFER_SIZE)
|
||||
PRINT_ERR("Buffer size exceed!");
|
||||
}
|
||||
|
||||
// ----
|
||||
// Static
|
||||
// ----
|
||||
|
||||
u8 IS_DMA_VIF1_INITIALIZED = 0;
|
||||
/** TODO */
|
||||
void VU1::uploadProgram(int t_dest, u32 *t_start, u32 *t_end)
|
||||
{
|
||||
if (!IS_DMA_VIF1_INITIALIZED)
|
||||
{
|
||||
IS_DMA_VIF1_INITIALIZED = 1;
|
||||
dma_channel_initialize(DMA_CHANNEL_VIF1, NULL, 0);
|
||||
dma_channel_fast_waits(DMA_CHANNEL_VIF1);
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
u8 tempBuffer[512] __attribute__((aligned(16)));
|
||||
void *chain = (u64 *)&tempBuffer; // uncached
|
||||
|
||||
// get the size of the code as we can only send 256 instructions in each MPGtag
|
||||
count = VU1::countProgramSize(t_start, t_end);
|
||||
while (count > 0)
|
||||
{
|
||||
u32 currentCount = count > 256 ? 256 : count;
|
||||
|
||||
*((u64 *)chain)++ = DMA_REF_TAG((u32)t_start, currentCount / 2);
|
||||
*((u32 *)chain)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||
*((u32 *)chain)++ = VIF_CODE(VIF_MPG, currentCount & 0xFF, t_dest);
|
||||
|
||||
t_start += currentCount * 2;
|
||||
count -= currentCount;
|
||||
t_dest += currentCount;
|
||||
}
|
||||
|
||||
*((u64 *)chain)++ = DMA_END_TAG(0);
|
||||
*((u32 *)chain)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||
*((u32 *)chain)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||
|
||||
// Send it to vif1
|
||||
FlushCache(0);
|
||||
dma_channel_send_chain(DMA_CHANNEL_VIF1, tempBuffer, 0, DMA_FLAG_TRANSFERTAG, 0);
|
||||
dma_channel_wait(DMA_CHANNEL_VIF1, VU1_DMA_CHAN_TIMEOUT); // synchronize immediately.
|
||||
}
|
||||
|
||||
u32 VU1::countProgramSize(u32 *t_start, u32 *t_end)
|
||||
{
|
||||
u32 size = (t_end - t_start) / 2;
|
||||
if (size & 1)
|
||||
size++;
|
||||
return size;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/utils/math.hpp"
|
||||
|
||||
#include <math.h>
|
||||
#include <fastmath.h>
|
||||
|
||||
float Math::cos(float x)
|
||||
{
|
||||
float r;
|
||||
asm volatile(
|
||||
"lui $9, 0x3f00 \n\t"
|
||||
".set noreorder \n\t"
|
||||
".align 3 \n\t"
|
||||
"abs.s %0, %1 \n\t"
|
||||
"lui $8, 0xbe22 \n\t"
|
||||
"mtc1 $9, $f1 \n\t"
|
||||
"ori $8, $8, 0xf983 \n\t"
|
||||
"mtc1 $8, $f8 \n\t"
|
||||
"lui $9, 0x4b00 \n\t"
|
||||
"mtc1 $9, $f3 \n\t"
|
||||
"lui $8, 0x3f80 \n\t"
|
||||
"mtc1 $8, $f2 \n\t"
|
||||
"mula.s %0, $f8 \n\t"
|
||||
"msuba.s $f3, $f2 \n\t"
|
||||
"madda.s $f3, $f2 \n\t"
|
||||
"lui $8, 0x40c9 \n\t"
|
||||
"msuba.s %0, $f8 \n\t"
|
||||
"ori $8, 0x0fdb \n\t"
|
||||
"msub.s %0, $f1, $f2 \n\t"
|
||||
"lui $9, 0xc225 \n\t"
|
||||
"abs.s %0, %0 \n\t"
|
||||
"lui $10, 0x3e80 \n\t"
|
||||
"mtc1 $10, $f7 \n\t"
|
||||
"ori $9, 0x5de1 \n\t"
|
||||
"sub.s %0, %0, $f7 \n\t"
|
||||
"lui $10, 0x42a3 \n\t"
|
||||
"mtc1 $8, $f3 \n\t"
|
||||
"ori $10, 0x3458 \n\t"
|
||||
"mtc1 $9, $f4 \n\t"
|
||||
"lui $8, 0xc299 \n\t"
|
||||
"mtc1 $10, $f5 \n\t"
|
||||
"ori $8, 0x2663 \n\t"
|
||||
"mul.s $f8, %0, %0 \n\t"
|
||||
"lui $9, 0x421e \n\t"
|
||||
"mtc1 $8, $f6 \n\t"
|
||||
"ori $9, 0xd7bb \n\t"
|
||||
"mtc1 $9, $f7 \n\t"
|
||||
"nop \n\t"
|
||||
"mul.s $f1, %0, $f8 \n\t"
|
||||
"mul.s $f9, $f8, $f8 \n\t"
|
||||
"mula.s $f3, %0 \n\t"
|
||||
"mul.s $f2, $f1, $f8 \n\t"
|
||||
"madda.s $f4, $f1 \n\t"
|
||||
"mul.s $f1, $f1, $f9 \n\t"
|
||||
"mul.s %0, $f2, $f9 \n\t"
|
||||
"madda.s $f5, $f2 \n\t"
|
||||
"madda.s $f6, $f1 \n\t"
|
||||
"madd.s %0, $f7, %0 \n\t"
|
||||
".set reorder \n\t"
|
||||
: "=&f"(r)
|
||||
: "f"(x)
|
||||
: "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$8", "$9", "$10");
|
||||
return r;
|
||||
}
|
||||
|
||||
float Math::sqrt(float x)
|
||||
{
|
||||
float r;
|
||||
__asm__ volatile(
|
||||
"sqrt.s %0, %1 \n\t"
|
||||
: "=&f"(r)
|
||||
: "f"(x));
|
||||
return r;
|
||||
}
|
||||
|
||||
float Math::invSqrt(float x) { return 1.0F / sqrt(x); }
|
||||
|
||||
/** Converts Vector3 to PS2SDK's Vector4 */
|
||||
void vec3ToNative(VECTOR o_result, Vector3 &t_vec, float t_fourthVal)
|
||||
{
|
||||
o_result[0] = t_vec.x;
|
||||
o_result[1] = t_vec.y;
|
||||
o_result[2] = t_vec.z;
|
||||
o_result[3] = t_fourthVal;
|
||||
}
|
||||
|
||||
/** Converts array of Vector3 to array of PS2SDK's Vector4 */
|
||||
void manyVec3ToNative(VECTOR *o_result, Vector3 *t_vec, int t_amount, float t_fourthVal)
|
||||
{
|
||||
for (int i = 0; i < t_amount; i++)
|
||||
vec3ToNative(o_result[i], t_vec[i], t_fourthVal);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../include/utils/string.hpp"
|
||||
#include <stdio.h>
|
||||
|
||||
char *String::createWithoutExtension(char *source)
|
||||
{
|
||||
u32 length = 0;
|
||||
for (;; length++)
|
||||
if (source[length] == '.')
|
||||
break;
|
||||
char *res = new char[length + 1];
|
||||
for (u32 i = 0; i < length; i++)
|
||||
res[i] = source[i];
|
||||
res[length] = '\0';
|
||||
return res;
|
||||
}
|
||||
|
||||
char *String::createCopy(char *source)
|
||||
{
|
||||
u32 srcLength = getLength(source);
|
||||
char *res = new char[srcLength + 1];
|
||||
for (u32 i = 0; i < srcLength; i++)
|
||||
res[i] = source[i];
|
||||
res[srcLength] = '\0';
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 String::getLength(char *a)
|
||||
{
|
||||
if (a == NULL)
|
||||
return 0;
|
||||
for (u32 i = 0;; i++)
|
||||
if (a[i] == '\0')
|
||||
return i;
|
||||
}
|
||||
|
||||
char *String::createConcatenated(char *a, char *b)
|
||||
{
|
||||
u32 aLength = getLength(a);
|
||||
u32 bLength = getLength(b);
|
||||
char *res = new char[aLength + bLength + 1]; // + '\0'
|
||||
for (u32 i = 0; i < aLength; i++)
|
||||
res[i] = a[i];
|
||||
for (u32 i = 0; i < bLength; i++)
|
||||
res[aLength + i] = b[i];
|
||||
res[aLength + bLength] = '\0';
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
; ______ ____ ___
|
||||
; | \/ ____| |___|
|
||||
; | | | \ | |
|
||||
;---------------------------
|
||||
; Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
; Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
;
|
||||
;---------------------------------------------------------------
|
||||
; draw3D.vcl |
|
||||
;---------------------------------------------------------------
|
||||
; A VU1 microprogram to draw 3D object using XYZ2, RGBAQ and ST|
|
||||
; This program uses double buffering (xtop) |
|
||||
; |
|
||||
; Many thanks to: |
|
||||
; - Dr Henry Fortuna |
|
||||
; - Jesper Svennevid, Daniel Collin |
|
||||
; - Guilherme Lampert |
|
||||
;---------------------------------------------------------------
|
||||
|
||||
; TODO
|
||||
; - Fix vertex clipping (is clipping visible triangles :/)
|
||||
; - Move lerp() from EE to VU1 (performance)
|
||||
; - Add dynamic lighting (feature)
|
||||
; - Add --cont + MSCNT instead of alltime MSCAL (performance)
|
||||
|
||||
.syntax new
|
||||
.name VU1Draw3D
|
||||
.vu
|
||||
.init_vf_all
|
||||
.init_vi_all
|
||||
|
||||
--enter
|
||||
--endenter
|
||||
|
||||
;//////////// --- Load data 1 --- /////////////
|
||||
; Updated once per frame
|
||||
lq matrixRow0, 0(vi00) ; load view-projection matrix
|
||||
lq matrixRow1, 1(vi00)
|
||||
lq matrixRow2, 2(vi00)
|
||||
lq matrixRow3, 3(vi00)
|
||||
;/////////////////////////////////////////////
|
||||
|
||||
fcset 0x000000 ; VCL won't let us use CLIP without first zeroing
|
||||
; the clip flags
|
||||
|
||||
;//////////// --- Load data 2 --- /////////////
|
||||
; Updated dynamically
|
||||
xtop iBase
|
||||
|
||||
lq.xyz scale, 0(iBase) ; load program params
|
||||
; float : X, Y, Z - scale vector that we will use to scale the verts after projecting them.
|
||||
; float : W - vert count.
|
||||
lq gifSetTag, 1(iBase) ; GIF tag - set
|
||||
lq texGifTag1, 2(iBase) ; GIF tag - texture LOD
|
||||
lq texGifTag2, 3(iBase) ; GIF tag - texture buffer & CLUT
|
||||
lq primTag, 4(iBase) ; GIF tag - tell GS how many data we will send
|
||||
lq rgba, 5(iBase) ; RGBA
|
||||
;lq clipScale, 6(iBase) ; TODO clipping tests
|
||||
; u32 : R, G, B, A (0-128)
|
||||
iaddiu vertexData, iBase, 7 ; pointer to vertex data
|
||||
ilw.w vertCount, 0(iBase) ; load vert count from scale vector
|
||||
iadd stqData, vertexData, vertCount ; pointer to stq
|
||||
iadd kickAddress, stqData, vertCount ; pointer for XGKICK
|
||||
iadd destAddress, stqData, vertCount ; helper pointer for data inserting
|
||||
;////////////////////////////////////////////
|
||||
|
||||
;/////////// --- Store tags --- /////////////
|
||||
sqi gifSetTag, (destAddress++) ;
|
||||
sqi texGifTag1, (destAddress++) ; texture LOD tag
|
||||
sqi gifSetTag, (destAddress++) ;
|
||||
sqi texGifTag2, (destAddress++) ; texture buffer & CLUT tag
|
||||
sqi primTag, (destAddress++) ; prim + tell gs how many data will be
|
||||
;////////////////////////////////////////////
|
||||
|
||||
;/////////////// --- Loop --- ///////////////
|
||||
iadd vertexCounter, iBase, vertCount ; loop vertCount times
|
||||
vertexLoop:
|
||||
|
||||
;////////// --- Load loop data --- //////////
|
||||
lq vertex, 0(vertexData) ; load xyz
|
||||
; float : X, Y, Z
|
||||
; any32 : _ = 0
|
||||
lq stq, 0(stqData) ; load stq
|
||||
; float : S, T
|
||||
; any32 : Q = 1 ; 1, because we will mul this by 1/vert[w] and this
|
||||
; will be our q for texture perspective correction
|
||||
; any32 : _ = 0
|
||||
;////////////////////////////////////////////
|
||||
|
||||
|
||||
;////////////// --- Vertex --- //////////////
|
||||
mul acc, matrixRow0, vertex[x] ; transform each vertex by the matrix
|
||||
madd acc, matrixRow1, vertex[y]
|
||||
madd acc, matrixRow2, vertex[z]
|
||||
madd vertex, matrixRow3, vertex[w]
|
||||
|
||||
;add.z acc, vf0, clipScale[w] ; TODO clipping maybe this?
|
||||
;madd.z clipVec, clipScale, vertex
|
||||
;mul.xy clipVec, clipScale, vertex
|
||||
;mul.w clipVec, vf0, vertex[z]
|
||||
|
||||
;mul.xyz clipVec, vertex, clipScale ; TODO clipping maybe this?
|
||||
|
||||
clipw.xyz vertex, vertex ; Dr. Fortuna: This instruction checks if the vertex is outside
|
||||
; the viewing frustum. If it is, then the appropriate
|
||||
; clipping flags are set
|
||||
fcand VI01, 0x3FFFF ; Bitwise AND the clipping flags with 0x3FFFF, this makes
|
||||
; sure that we get the clipping judgement for the last three
|
||||
; verts (i.e. that make up the triangle we are about to draw)
|
||||
iaddiu iADC, VI01, 0x7FFF ; Add 0x7FFF. If any of the clipping flags were set this will
|
||||
; cause the triangle not to be drawn (any values above 0x8000
|
||||
; that are stored in the w component of XYZ2 will set the ADC
|
||||
; bit, which tells the GS not to perform a drawing kick on this
|
||||
; triangle.
|
||||
|
||||
;ilw.w iNoDraw, UVStart(Counter) ; Load the iNoDraw flag. If true we should set the ADC bit so the vert isn't drawn
|
||||
;iadd iADC, iADC, iNoDraw ; TODO clipping maybe this?
|
||||
|
||||
isw.w iADC, 2(destAddress)
|
||||
|
||||
div q, vf00[w], vertex[w] ; perspective divide (1/vert[w]):
|
||||
mul.xyz vertex, vertex, q
|
||||
mula.xyz acc, scale, vf00[w] ; scale to GS screen space
|
||||
madd.xyz vertex, vertex, scale ; multiply and add the scales -> vert = vert * scale + scale
|
||||
ftoi4.xyz vertex, vertex ; convert vertex to 12:4 fixed point format
|
||||
;////////////////////////////////////////////
|
||||
|
||||
|
||||
;//////////////// --- ST --- ////////////////
|
||||
mulq modStq, stq, q
|
||||
;////////////////////////////////////////////
|
||||
|
||||
|
||||
;//////////// --- Store data --- ////////////
|
||||
sq modStq, 0(destAddress) ; STQ
|
||||
sq rgba, 1(destAddress) ; RGBA ; q is grabbed from stq
|
||||
sq.xyz vertex, 2(destAddress) ; XYZ2
|
||||
;////////////////////////////////////////////
|
||||
|
||||
iaddiu vertexData, vertexData, 1
|
||||
iaddiu stqData, stqData, 1
|
||||
iaddiu destAddress, destAddress, 3
|
||||
|
||||
iaddi vertexCounter, vertexCounter, -1 ; decrement the loop counter
|
||||
ibne vertexCounter, iBase, vertexLoop ; and repeat if needed
|
||||
|
||||
;////////////////////////////////////////////
|
||||
|
||||
--barrier
|
||||
|
||||
xgkick kickAddress ; dispatch to the GS rasterizer.
|
||||
|
||||
--exit
|
||||
--endexit
|
||||
@@ -0,0 +1,75 @@
|
||||
;-------------------------
|
||||
;-------------------------
|
||||
;-----VCL CODE------------
|
||||
;-------------------------
|
||||
;-------------------------
|
||||
; =================================================
|
||||
; flowMon::Emit() vcl 1.4beta7 produced this code:
|
||||
.vu
|
||||
.align 4
|
||||
.global VU1Draw3D_CodeStart
|
||||
.global VU1Draw3D_CodeEnd
|
||||
VU1Draw3D_CodeStart:
|
||||
__v_draw3D_vcl_4:
|
||||
; _LNOPT_w=[ normal2 ] 23 [23 0] 23 [__v_draw3D_vcl_4]
|
||||
NOP lq VF01,0(VI00)
|
||||
NOP xtop VI02
|
||||
NOP lq VF02,1(VI00)
|
||||
NOP lq VF06,1(VI02)
|
||||
NOP lq VF09,2(VI02)
|
||||
NOP lq VF08,3(VI02)
|
||||
NOP lq VF07,4(VI02)
|
||||
NOP lq VF03,2(VI00)
|
||||
NOP iaddiu VI03,VI02,0x00000007
|
||||
NOP ilw.w VI07,0(VI02)
|
||||
NOP lq VF04,3(VI00)
|
||||
NOP fcset 0
|
||||
NOP lq.xyz VF05,0(VI02)
|
||||
NOP iadd VI04,VI03,VI07
|
||||
NOP iadd VI06,VI04,VI07
|
||||
NOP sqi VF06,(VI06++)
|
||||
NOP sqi VF09,(VI06++)
|
||||
NOP sqi VF06,(VI06++)
|
||||
NOP sqi VF08,(VI06++)
|
||||
NOP lq VF06,5(VI02)
|
||||
NOP iadd VI05,VI04,VI07
|
||||
NOP sqi VF07,(VI06++)
|
||||
NOP iadd VI07,VI02,VI07
|
||||
vertexLoop:
|
||||
; _LNOPT_w=[ normal2 ] 21 [31 14] 31 [vertexLoop]
|
||||
NOP lq VF07,0(VI03)
|
||||
mulax ACC,VF01,VF07x sq VF06,1(VI06) ; STALL_LATENCY ?3
|
||||
madday ACC,VF02,VF07y lq VF08,0(VI04)
|
||||
maddaz ACC,VF03,VF07z iaddiu VI06,VI06,0x00000003
|
||||
maddw VF07,VF04,VF07w NOP
|
||||
clipw.xyz VF07xyz,VF07w div Q,VF00w,VF07w ; STALL_LATENCY ?3
|
||||
NOP NOP
|
||||
NOP NOP
|
||||
NOP NOP
|
||||
NOP NOP
|
||||
NOP NOP
|
||||
NOP NOP
|
||||
mulq.xyz VF07,VF07,Q fcand VI01,262143
|
||||
mulaw.xyz ACC,VF05,VF00w iaddiu VI03,VI03,0x00000001
|
||||
madd.xyz VF07,VF07,VF05 iaddiu VI04,VI04,0x00000001 ; STALL_LATENCY ?2
|
||||
mulq VF08,VF08,Q isubiu VI07,VI07,1
|
||||
ftoi4.xyz VF07,VF07 iaddiu VI01,VI01,0x00007fff ; STALL_LATENCY ?2
|
||||
NOP isw.w VI01,-1(VI06)
|
||||
NOP sq VF08,-3(VI06)
|
||||
NOP ibne VI07,VI02,vertexLoop
|
||||
NOP sq.xyz VF07,-1(VI06)
|
||||
; _LNOPT_w=[ normal2 ] 3 [1 0] 3 [__v_draw3D_vcl_7]
|
||||
NOP xgkick VI05
|
||||
NOP[E] NOP
|
||||
NOP NOP
|
||||
.align 4
|
||||
VU1Draw3D_CodeEnd:
|
||||
; iCount=47
|
||||
; register stats:
|
||||
; 8 VU User integer
|
||||
; 10 VU User floating point
|
||||
;-------------------------
|
||||
;-------------------------
|
||||
;-------------------------
|
||||
;-------------------------
|
||||
;-------------------------
|
||||
Reference in New Issue
Block a user