Implement runtime texture loading

This commit is contained in:
Daniel Ramírez 2025-05-21 03:23:47 +02:00
parent f22b9e1bb6
commit cb1d89065f
26 changed files with 590 additions and 272 deletions

View File

@ -5,9 +5,30 @@
MeshFilter::MeshFilter(const FString &path) {
// Load the mesh from the file
auto vertices = Utils::File::ReadObjFile(path);
auto [shapes, materials] = Utils::File::ReadObjFile(path);
mesh = LoadResource<Mesh>(vertices);
TVector<PtrShr<Texture>> textures;
for (const auto &material : materials) {
auto texture_binary = Utils::File::ReadBinaryFile<unsigned int>(
path.substr(0, path.find_last_of("/"))
.append("/")
.append(material.diffuse_texname.substr(
0, material.diffuse_texname.find_last_of(".")))
.append(".img.bin"));
// auto palette_binary = Utils::File::ReadBinaryFile<unsigned short>(
// path.substr(0, path.find_last_of("/"))
// .append("/")
// .append(material.diffuse_texname.substr(
// 0, material.diffuse_texname.find_last_of(".")))
// .append(".pal.bin"));
auto palette_binary = TVector<unsigned short>();
textures.push_back(LoadResource<Texture>(texture_binary, palette_binary));
}
mesh = LoadResource<Mesh>(shapes, materials, textures);
}
PtrUnq<MeshFilter> MeshFilter::Initialize(const FString &path) {

View File

@ -44,12 +44,19 @@ PtrUnq<Engine> &Engine::GetInstance() {
}
void Engine::run() {
// TEST ------------------------
Renderer::GetInstance();
// TEST ------------------------
// Create a MeshInstance3D
PtrShr<MeshInstance3D> meshInstance =
NewNode<MeshInstance3D>("meshes/mococo/mococo.obj");
// PtrShr<MeshInstance3D> meshIPnstance =
// NewNode<MeshInstance3D>("meshes/cube/cube-tex.obj");
// PtrShr<MeshInstance3D> meshInstance =
// NewNode<MeshInstance3D>("meshes/quad/quad.obj");
// -----------------------------
while (pmMainLoop()) {
@ -63,6 +70,9 @@ void Engine::processInput() { Input::Update(); }
void Engine::update() {
// Update
if (Input::IsButtonDown(EButton::A)) {
iprintf("A button pressed\n");
}
}
void Engine::render() {
@ -84,8 +94,7 @@ void Engine::render() {
Engine::Engine() {
// Initialize nitroFS
char nitroFSPath[32];
strcpy(nitroFSPath, "assets");
char nitroFSPath[] = {"assets"};
char *nitroFSPathptr = nitroFSPath;
if (!nitroFSInit(&nitroFSPathptr))
exit(-1);

View File

@ -7,6 +7,8 @@
#include <nds.h>
#include <stdio.h>
#include "input/input.h"
PtrUnq<Renderer> Renderer::Instance;
PtrUnq<Renderer> &Renderer::GetInstance() {
@ -16,34 +18,45 @@ PtrUnq<Renderer> &Renderer::GetInstance() {
return Instance;
}
// TEST -------------------
float rotation = 45.f;
// TEST -------------------
void Renderer::beginFrame() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70, 256.0 / 192.0, 0.1, 100);
// glPolyFmt(POLY_ALPHA(31) | POLY_CULL_BACK);
// glMatrixMode(GL_TEXTURE);
// glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix(); // Save the current matrix state
glPolyFmt(POLY_ALPHA(31) | POLY_CULL_BACK);
glLoadIdentity(); // Load the identity matrix
// TEST -------------------
if (Input::IsButtonHeld(EButton::LEFT))
rotation++;
if (Input::IsButtonHeld(EButton::RIGHT))
rotation--;
// TEST -------------------
// Render scene
glTranslatef(0.f, 0.f, -4.f); // Move the camera back
glRotatef(45, 1, 1, 0); // Rotation
glTranslatef(0.f, -.75f, -2.f); // Move the camera back
glRotatef(rotation, 1, 1, 0); // Rotation
}
void Renderer::render(const Transform &transform,
const MeshFilter &meshFilter) {
// drawCube(1.0f); // Draw a cube
glPolyFmt(POLY_ALPHA(31) | POLY_CULL_BACK);
glBindTexture(0, meshFilter.getMesh()->getTextures()[0]->getId());
glBegin(GL_TRIANGLES);
for (const auto &shapes : meshFilter.getMesh()->getVertices()) {
for (const auto &vertex : shapes) {
glColor3f(1.0, 0.0, 0.0); // Red
glVertex3f(vertex.position.x, vertex.position.y, vertex.position.z);
glNormal3f(vertex.normal.x, vertex.normal.y, vertex.normal.z);
glColor3b(255, 255, 255);
for (const auto &shape : meshFilter.getMesh()->getShapes()) {
for (const auto &vertex : shape.vertices) {
// glNormal3f(vertex.normal.x, vertex.normal.y, vertex.normal.z);
glTexCoord2f(vertex.texCoords.x, vertex.texCoords.y);
glVertex3f(vertex.position.x, vertex.position.y, vertex.position.z);
}
}
@ -113,16 +126,27 @@ Renderer::Renderer() {
lcdMainOnTop(); // Set the main screen on top
videoSetMode(MODE_0_3D); // Set 3D rendering mode
videoSetModeSub(MODE_5_2D); // Set 2D rendering mode for the sub-screen
vramSetBankA(VRAM_A_MAIN_BG); // Allocate VRAM for textures
vramSetBankB(VRAM_B_TEXTURE);
vramSetBankC(VRAM_C_TEXTURE);
vramSetBankD(VRAM_D_TEXTURE);
vramSetBankE(VRAM_E_TEX_PALETTE);
vramSetBankF(VRAM_F_LCD);
// vramSetBankG(VRAM_G_TEX_PALETTE);
// Initialize the 3D engine
glInit();
glEnable(GL_TEXTURE_2D);
glViewport(0, 0, 255, 191); // Set viewport
glEnable(GL_ANTIALIAS);
glClearColor(0, 0, 0, 31); // Set clear color (black)
glClearPolyID(63); // Set default polygon ID
glClearDepth(GL_MAX_DEPTH); // Set clear depth
glViewport(0, 0, 255, 191); // Set viewport
glEnable(GL_BLEND);
vramSetBankA(VRAM_A_TEXTURE); // Allocate VRAM for textures
vramSetBankB(VRAM_B_LCD);
// Debug
consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 23, 2, false, true);
consoleDemoInit();
}

View File

@ -4,20 +4,20 @@
#include <stdio.h>
// Static members
u32 Input::KeysHeldState = 0;
u32 Input::KeysDownState = 0;
u32 Input::KeysUpState = 0;
u32 Input::ButtonsHeldState = 0;
u32 Input::ButtonsDownState = 0;
u32 Input::ButtonsUpState = 0;
void Input::Update() {
// Update key states
scanKeys();
KeysHeldState = keysHeld();
KeysDownState = keysDown();
KeysUpState = keysUp();
ButtonsHeldState = keysHeld();
ButtonsDownState = keysDown();
ButtonsUpState = keysUp();
}
bool Input::IsKeyHeld(EKey key) { return KeysHeldState & key; }
bool Input::IsButtonHeld(EButton key) { return ButtonsHeldState & key; }
bool Input::IsKeyDown(EKey key) { return KeysDownState & key; }
bool Input::IsButtonDown(EButton key) { return ButtonsDownState & key; }
bool Input::IsKeyUp(EKey key) { return KeysUpState & key; }
bool Input::IsButtonUp(EButton key) { return ButtonsUpState & key; }

View File

@ -1,8 +1,11 @@
#include "resources/mesh.h"
Mesh Mesh::Load(const TVector<TVector<FVertex>> &vertices) {
return std::move(Mesh(vertices));
Mesh Mesh::Load(const TVector<FShape> &shapes,
const TVector<FMaterial> &materials,
const TVector<PtrShr<Texture>> &textures) {
return std::move(Mesh(shapes, materials, textures));
}
Mesh::Mesh(const TVector<TVector<FVertex>> &vertices)
: Super(), vertices(vertices) {}
Mesh::Mesh(const TVector<FShape> &shapes, const TVector<FMaterial> &materials,
const TVector<PtrShr<Texture>> &textures)
: Super(), shapes(shapes), materials(materials), textures(textures) {}

View File

@ -0,0 +1,27 @@
#include "resources/texture.h"
#include <nds/arm9/videoGL.h>
Texture::~Texture() {
// TODO: Check what the hell is happening here
// glBindTexture(0, id);
// glColorTableEXT(0, 0, 0, 0, 0, nullptr);
// glDeleteTextures(1, &id);
// iprintf("Texture %d deleted\n", id);
}
Texture Texture::Load(TVector<unsigned int> &data,
TVector<unsigned short> &palette) {
return Texture(data, palette);
}
Texture::Texture(TVector<unsigned int> &data, TVector<unsigned short> &palette)
: Super() {
glGenTextures(1, &id);
glBindTexture(0, id);
// TODO: Manage different texture formats
glTexImage2D(0, 0, GL_RGBA, TEXTURE_SIZE_128, TEXTURE_SIZE_128, 0,
TEXGEN_TEXCOORD, (u8 *)data.data());
// glColorTableEXT(0, 0, 32, 0, 0, (u16 *)palette.data());
}

View File

@ -2,6 +2,7 @@
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"
#include <algorithm>
namespace Utils::File {
@ -11,15 +12,13 @@ FString ReadTextFile(const FString &path) {
FString result;
FILE *f = fopen(AssetPath(path).c_str(), "rb");
if (!f) {
iprintf("No se pudo abrir el archivo\n");
// TODO: iprintf("No se pudo abrir el archivo\n");
} else {
iprintf("Archivo abierto\n");
fseek(f, 0, SEEK_END);
size_t size = ftell(f);
rewind(f);
TVector<uint8_t> buffer(size);
TVector<u8> buffer(size);
fread(buffer.data(), 1, size, f);
fclose(f);
@ -30,28 +29,29 @@ FString ReadTextFile(const FString &path) {
return std::move(result);
}
TVector<TVector<FVertex>> ReadObjFile(const FString &path) {
TTuple<TVector<FShape>, TVector<FMaterial>> ReadObjFile(const FString &path) {
FString nitroPath = AssetPath(path);
FString baseFolder =
nitroPath.substr(0, nitroPath.find_last_of("/")).append("/");
tinyobj::attrib_t attrib;
TVector<tinyobj::shape_t> shapes;
TVector<tinyobj::material_t> materials;
FString err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err,
AssetPath(path).c_str(),
AssetPath(path + "/..").c_str(), true);
nitroPath.c_str(), baseFolder.c_str(), true);
if (ret)
iprintf("Cargado correctamente\n");
else
iprintf("Error al cargar el archivo: %s\n", err.c_str());
if (!ret) {
// TODO: print error
return {TVector<FShape>(), TVector<FMaterial>()};
}
iprintf("Numero de materiales: %d\n", materials.size());
TVector<TVector<FVertex>> vertices;
TVector<FShape> shape_vertices;
// Loop over shapes
for (size_t s = 0; s < shapes.size(); s++) {
vertices.push_back({});
shape_vertices.push_back({});
// Loop over faces(polygon)
size_t index_offset = 0;
for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) {
@ -88,20 +88,23 @@ TVector<TVector<FVertex>> ReadObjFile(const FString &path) {
tinyobj::real_t ty =
attrib.texcoords[2 * size_t(idx.texcoord_index) + 1];
// I lost 3 days bacause of this :')
ty = 1.0f - std::clamp(ty, 0.0f, 1.0f);
texCoords = FVector2(tx, ty);
}
vertices[s].push_back(FVertex(positions, normals, texCoords));
shape_vertices[s].vertices.push_back(
FVertex(positions, normals, texCoords));
}
index_offset += fv;
// per-face material
// shapes[s].mesh.material_ids[f];
// shape_materials.push_back(materials[shapes[s].mesh.material_ids[f]]);
}
}
return std::move(vertices);
return {shape_vertices, materials};
}
} // namespace Utils::File

View File

@ -23,6 +23,7 @@ THE SOFTWARE.
*/
//
// xrbDS 0.1 : Change TINYOBJ_SSCANF_BUFFER_SIZE to 512
// version 1.0.6 : Add TINYOBJLOADER_USE_DOUBLE option(#124)
// version 1.0.5 : Ignore `Tr` when `d` exists in MTL(#43)
// version 1.0.4 : Support multiple filenames for 'mtllib'(#112)
@ -98,11 +99,11 @@ namespace tinyobj {
// cube_left | cube_right
#ifdef TINYOBJLOADER_USE_DOUBLE
//#pragma message "using double"
typedef double real_t;
// #pragma message "using double"
typedef double real_t;
#else
//#pragma message "using float"
typedef float real_t;
// #pragma message "using float"
typedef float real_t;
#endif
typedef enum {
@ -254,18 +255,12 @@ typedef struct callback_t_ {
void (*object_cb)(void *user_data, const char *name);
callback_t_()
: vertex_cb(NULL),
normal_cb(NULL),
texcoord_cb(NULL),
index_cb(NULL),
usemtl_cb(NULL),
mtllib_cb(NULL),
group_cb(NULL),
object_cb(NULL) {}
: vertex_cb(NULL), normal_cb(NULL), texcoord_cb(NULL), index_cb(NULL),
usemtl_cb(NULL), mtllib_cb(NULL), group_cb(NULL), object_cb(NULL) {}
} callback_t;
class MaterialReader {
public:
public:
MaterialReader() {}
virtual ~MaterialReader();
@ -276,7 +271,7 @@ class MaterialReader {
};
class MaterialFileReader : public MaterialReader {
public:
public:
explicit MaterialFileReader(const std::string &mtl_basedir)
: m_mtlBaseDir(mtl_basedir) {}
virtual ~MaterialFileReader() {}
@ -284,12 +279,12 @@ class MaterialFileReader : public MaterialReader {
std::vector<material_t> *materials,
std::map<std::string, int> *matMap, std::string *err);
private:
private:
std::string m_mtlBaseDir;
};
class MaterialStreamReader : public MaterialReader {
public:
public:
explicit MaterialStreamReader(std::istream &inStream)
: m_inStream(inStream) {}
virtual ~MaterialStreamReader() {}
@ -297,7 +292,7 @@ class MaterialStreamReader : public MaterialReader {
std::vector<material_t> *materials,
std::map<std::string, int> *matMap, std::string *err);
private:
private:
std::istream &m_inStream;
};
@ -361,7 +356,7 @@ namespace tinyobj {
MaterialReader::~MaterialReader() {}
#define TINYOBJ_SSCANF_BUFFER_SIZE (4096)
#define TINYOBJ_SSCANF_BUFFER_SIZE (512)
struct vertex_index {
int v_idx, vt_idx, vn_idx;
@ -404,11 +399,13 @@ static std::istream &safeGetline(std::istream &is, std::string &t) {
case '\n':
return is;
case '\r':
if (sb->sgetc() == '\n') sb->sbumpc();
if (sb->sgetc() == '\n')
sb->sbumpc();
return is;
case EOF:
// Also handle the case when the last line has no line ending
if (t.empty()) is.setstate(std::ios::eofbit);
if (t.empty())
is.setstate(std::ios::eofbit);
return is;
default:
t += static_cast<char>(c);
@ -423,8 +420,10 @@ static std::istream &safeGetline(std::istream &is, std::string &t) {
// Make index zero-base, and also support relative index.
static inline int fixIndex(int idx, int n) {
if (idx > 0) return idx - 1;
if (idx == 0) return 0;
if (idx > 0)
return idx - 1;
if (idx == 0)
return 0;
return n + idx; // negative value = relative
}
@ -521,9 +520,11 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) {
}
// We must make sure we actually got something.
if (read == 0) goto fail;
if (read == 0)
goto fail;
// We allow numbers of form "#", "###" etc.
if (!end_not_reached) goto assemble;
if (!end_not_reached)
goto assemble;
// Read the decimal part.
if (*curr == '.') {
@ -548,7 +549,8 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) {
goto assemble;
}
if (!end_not_reached) goto assemble;
if (!end_not_reached)
goto assemble;
// Read the exponent part.
if (*curr == 'e' || *curr == 'E') {
@ -574,13 +576,14 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) {
end_not_reached = (curr != s_end);
}
exponent *= (exp_sign == '+' ? 1 : -1);
if (read == 0) goto fail;
if (read == 0)
goto fail;
}
assemble:
*result =
(sign == '+' ? 1 : -1) *
(exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent) : mantissa);
*result = (sign == '+' ? 1 : -1) *
(exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent)
: mantissa);
return true;
fail:
return false;
@ -603,8 +606,8 @@ static inline void parseReal2(real_t *x, real_t *y, const char **token,
(*y) = parseReal(token, default_y);
}
static inline void parseReal3(real_t *x, real_t *y, real_t *z, const char **token,
const double default_x = 0.0,
static inline void parseReal3(real_t *x, real_t *y, real_t *z,
const char **token, const double default_x = 0.0,
const double default_y = 0.0,
const double default_z = 0.0) {
(*x) = parseReal(token, default_x);
@ -638,8 +641,9 @@ static inline bool parseOnOff(const char **token, bool default_value = true) {
return ret;
}
static inline texture_type_t parseTextureType(
const char **token, texture_type_t default_value = TEXTURE_TYPE_NONE) {
static inline texture_type_t
parseTextureType(const char **token,
texture_type_t default_value = TEXTURE_TYPE_NONE) {
(*token) += strspn((*token), " \t");
const char *end = (*token) + strcspn((*token), " \t\r");
texture_type_t ty = default_value;
@ -887,8 +891,9 @@ static void InitMaterial(material_t *material) {
material->unknown_parameter.clear();
}
static bool exportFaceGroupToShape(
shape_t *shape, const std::vector<std::vector<vertex_index> > &faceGroup,
static bool
exportFaceGroupToShape(shape_t *shape,
const std::vector<std::vector<vertex_index>> &faceGroup,
const std::vector<tag_t> &tags, const int material_id,
const std::string &name, bool triangulate) {
if (faceGroup.empty()) {
@ -1004,9 +1009,11 @@ void LoadMtl(std::map<std::string, int> *material_map,
token += strspn(token, " \t");
assert(token);
if (token[0] == '\0') continue; // empty line
if (token[0] == '\0')
continue; // empty line
if (token[0] == '#') continue; // comment line
if (token[0] == '#')
continue; // comment line
// new mtl
if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) {
@ -1431,7 +1438,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
std::vector<real_t> vn;
std::vector<real_t> vt;
std::vector<tag_t> tags;
std::vector<std::vector<vertex_index> > faceGroup;
std::vector<std::vector<vertex_index>> faceGroup;
std::string name;
// material
@ -1464,9 +1471,11 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
token += strspn(token, " \t");
assert(token);
if (token[0] == '\0') continue; // empty line
if (token[0] == '\0')
continue; // empty line
if (token[0] == '#') continue; // comment line
if (token[0] == '#')
continue; // comment line
// vertex
if (token[0] == 'v' && IS_SPACE((token[1]))) {
@ -1564,8 +1573,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
if (filenames.empty()) {
if (err) {
(*err) +=
"WARN: Looks like empty filename for mtllib. Use default "
(*err) += "WARN: Looks like empty filename for mtllib. Use default "
"material. \n";
}
} else {
@ -1586,8 +1594,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
if (!found) {
if (err) {
(*err) +=
"WARN: Failed to load material file(s). Use default "
(*err) += "WARN: Failed to load material file(s). Use default "
"material.\n";
}
}
@ -1770,9 +1777,11 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
token += strspn(token, " \t");
assert(token);
if (token[0] == '\0') continue; // empty line
if (token[0] == '\0')
continue; // empty line
if (token[0] == '#') continue; // comment line
if (token[0] == '#')
continue; // comment line
// vertex
if (token[0] == 'v' && IS_SPACE((token[1]))) {
@ -1873,8 +1882,7 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
if (filenames.empty()) {
if (err) {
(*err) +=
"WARN: Looks like empty filename for mtllib. Use default "
(*err) += "WARN: Looks like empty filename for mtllib. Use default "
"material. \n";
}
} else {
@ -1895,8 +1903,7 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
if (!found) {
if (err) {
(*err) +=
"WARN: Failed to load material file(s). Use default "
(*err) += "WARN: Failed to load material file(s). Use default "
"material.\n";
}
} else {

View File

@ -19,9 +19,11 @@
#include <bits/unique_ptr.h>
#include <bits/shared_ptr.h>
#include <calico/types.h>
#include <tiny_obj_loader.h>
#include <array>
#include <vector>
#include <string>
#include <tuple>
/////////////////////////////////////
// MEMORY
@ -71,6 +73,17 @@ template <typename T> using TVector = std::vector<T>;
* @tparam S The size of the array.
*/
template <typename T, size_t S> using TArray = std::array<T, S>;
/**
* @brief Alias template for creating a std::tuple with a variadic list of
* types.
*
* This alias simplifies the usage of std::tuple by allowing the user to write
* TTuple<T...> instead of std::tuple<T...>.
*
* @tparam T... Variadic template parameter pack representing the types to be
* included in the tuple.
*/
template <typename... T> using TTuple = std::tuple<T...>;
/////////////////////////////////////
// BASIC TYPES
@ -141,4 +154,10 @@ using FVector3 = glm::vec3;
*/
using FVector3Int = glm::ivec3;
/////////////////////////////////////
// SHAPES
/////////////////////////////////////
using FMaterial = tinyobj::material_t;
#endif // XRBDS_CORE_TYPES_H

View File

@ -6,7 +6,7 @@
*
* This header defines the Input class, which provides static methods to query
* the state of keys (held, pressed, or released) on the system. It also defines
* the EKey enumeration for representing individual keys.
* the EButton enumeration for representing individual keys.
*
* The Input class is designed as a utility class and cannot be instantiated.
* It maintains internal states for keys and provides methods to update and
@ -14,8 +14,8 @@
*
* Usage:
* - Call Input::Update() periodically to refresh the key states.
* - Use Input::IsKeyHeld(), Input::IsKeyDown(), or Input::IsKeyUp() to query
* the state of specific keys.
* - Use Input::IsButtonHeld(), Input::IsButtonDown(), or Input::IsButtonUp() to
* query the state of specific keys.
*
* @author Daniel Ramirez Morilla
* @date 2025-04-19
@ -33,7 +33,7 @@
#include <nds/input.h>
/**
* @enum EKey
* @enum EButton
* @brief Represents the keys available on the NDS platform.
*
* This enumeration defines constants for each key on the NDS system, mapping
@ -44,7 +44,7 @@
*
* Example usage:
* @code
* if (Input::IsKeyDown(EKey::A)) {
* if (Input::IsButtonDown(EButton::A)) {
* // Handle A button press
* }
* @endcode
@ -52,7 +52,7 @@
* @note These key codes are specific to the NDS platform and rely on the
* platform's key definitions.
*/
enum EKey : u16 {
enum EButton : u16 {
A = KEY_A,
B = KEY_B,
X = KEY_X,
@ -70,9 +70,9 @@ enum EKey : u16 {
/**
* @class Input
* @brief Provides static methods to handle input states for keys.
* @brief Provides static methods to handle input states for buttons.
*
* The Input class is a utility class that allows querying the state of keys
* The Input class is a utility class that allows querying the state of buttons
* (held, pressed, or released) using static methods. It is not meant to be
* instantiated.
*/
@ -81,46 +81,47 @@ public:
/**
* @brief Updates the internal state of the input system.
*
* This method should be called periodically to refresh the key states.
* This method should be called periodically to refresh the button states.
*/
static void Update();
/**
* @brief Checks if a specific key is currently being held down.
* @param key The key to check.
* @return True if the key is held down, false otherwise.
* @brief Checks if a specific button is currently being held down.
* @param button The button to check.
* @return True if the button is held down, false otherwise.
*/
static bool IsKeyHeld(EKey key);
static bool IsButtonHeld(EButton button);
/**
* @brief Checks if a specific key was pressed in the current update cycle.
* @param key The key to check.
* @return True if the key was pressed, false otherwise.
* @brief Checks if a specific button was pressed in the current update cycle.
* @param button The button to check.
* @return True if the button was pressed, false otherwise.
*/
static bool IsKeyDown(EKey key);
static bool IsButtonDown(EButton button);
/**
* @brief Checks if a specific key was released in the current update cycle.
* @param key The key to check.
* @return True if the key was released, false otherwise.
* @brief Checks if a specific button was released in the current update
* cycle.
* @param button The button to check.
* @return True if the button was released, false otherwise.
*/
static bool IsKeyUp(EKey key);
static bool IsButtonUp(EButton button);
private:
/**
* @brief Stores the state of keys currently being held down.
* @brief Stores the state of buttons currently being held down.
*/
static u32 KeysHeldState;
static u32 ButtonsHeldState;
/**
* @brief Stores the state of keys pressed in the current update cycle.
* @brief Stores the state of buttons pressed in the current update cycle.
*/
static u32 KeysDownState;
static u32 ButtonsDownState;
/**
* @brief Stores the state of keys released in the current update cycle.
* @brief Stores the state of buttons released in the current update cycle.
*/
static u32 KeysUpState;
static u32 ButtonsUpState;
/**
* @brief Deleted constructor to prevent instantiation of the Input class.

View File

@ -3,6 +3,7 @@
#include "resource.h"
#include "core/types.h"
#include "resources/texture.h"
#include <vector>
@ -15,19 +16,30 @@ struct FVertex {
: position(pos), normal(norm), texCoords(tex) {}
};
struct FShape {
TVector<FVertex> vertices;
};
class Mesh : public Resource {
using Super = Resource;
public:
static Mesh Load(const TVector<TVector<FVertex>> &vertices);
static Mesh Load(const TVector<FShape> &shapes,
const TVector<FMaterial> &materials,
const TVector<PtrShr<Texture>> &textures);
TVector<TVector<FVertex>> getVertices() const { return vertices; }
const TVector<FShape> &getShapes() const { return shapes; }
const TVector<FMaterial> &getMaterials() const { return materials; }
const TVector<PtrShr<Texture>> &getTextures() const { return textures; }
private:
TVector<TVector<FVertex>> vertices;
TVector<FShape> shapes;
TVector<FMaterial> materials;
TVector<PtrShr<Texture>> textures;
Mesh() = default;
Mesh(const TVector<TVector<FVertex>> &vertices);
Mesh(const TVector<FShape> &shapes, const TVector<FMaterial> &materials,
const TVector<PtrShr<Texture>> &textures);
};
#endif // XRBDS_RESOURCES_MESH_H

View File

@ -0,0 +1,46 @@
#ifndef XRBDS_RESOURCES_TEXTURE_H
#define XRBDS_RESOURCES_TEXTURE_H
#include "resource.h"
#include "core/types.h"
/**
* @class Texture
* @brief Represents a texture resource that includes pixel data and a color
* palette.
*
* The Texture class is derived from the Resource class and provides
* functionality to load and manage texture data and its associated palette. It
* also provides access to the texture's unique identifier.
*/
class Texture : public Resource {
using Super = Resource;
public:
virtual ~Texture();
/**
* @brief Loads a texture from the given pixel data and palette.
*
* @param data A reference to a vector containing the texture's pixel data.
* @param palette A reference to a vector containing the texture's color
* palette.
* @return A Texture object initialized with the provided data and palette.
*/
static Texture Load(TVector<unsigned int> &data,
TVector<unsigned short> &palette);
/**
* @brief Retrieves the unique identifier of the texture.
*
* @return The unique identifier of the texture as an unsigned 8-bit integer.
*/
const u8 getId() { return id; }
private:
Texture(TVector<unsigned int> &data, TVector<unsigned short> &palette);
int id;
};
#endif // XRBDS_RESOURCES_TEXTURE_H

View File

@ -4,8 +4,14 @@
#include "core/types.h"
#include "resources/mesh.h"
struct FObjData {
TVector<TVector<FVertex>> vertices;
};
namespace Utils::File {
FString AssetPath(const FString &path);
/**
* @brief Reads the contents of a text file and returns it as a string.
*
@ -20,13 +26,38 @@ FString ReadTextFile(const FString &path);
* vector of vertices.
*
* @param path The file path to the OBJ file as an FString.
* @return A TVector of TVector of FVertex, where each inner vector represents a
* group of vertices.
* @return A TVector of TVector of FVertex, where each inner vector represents
* a group of vertices.
*
* @note Ensure the file at the specified path exists and is in a valid OBJ
* format.
*/
TVector<TVector<FVertex>> ReadObjFile(const FString &path);
TTuple<TVector<FShape>, TVector<FMaterial>> ReadObjFile(const FString &path);
/**
* @brief Reads a binary file and returns its contents as a TVector of type T.
*
* @tparam T The type of data to read from the binary file.
* @param path The file path to the binary file to be read.
* @return TVector<T> A vector containing the contents of the binary file.
*/
template <typename T> TVector<T> ReadBinaryFile(const FString &path) {
FILE *file = fopen(AssetPath(path).c_str(), "rb");
if (!file) {
// TODO: iprintf("Error abriendo: %s\n", path.c_str());
return {};
}
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
rewind(file);
TVector<T> buffer(size);
fread(buffer.data(), 1, size, file);
fclose(file);
return buffer;
}
} // namespace Utils::File

View File

@ -0,0 +1,98 @@
# cube-tex.obj
# Import into Blender with Y-forward, Z-up
#
# Vertices: Faces:
# f-------g +-------+
# /. /| /. 5 /| 3 back
# / . / | / . / |
# e-------h | 2 +-------+ 1|
# | b . .|. c z right | . . .|. +
# | . | / | /y | . 4 | /
# |. |/ |/ |. |/
# a-------d +---- x +-------+
# 6
# bottom
# Material defined in separate file.
mtllib cube.mtl
g cube
# Vertices
v 0.0 0.0 0.0 # 1 a
v 0.0 1.0 0.0 # 2 b
v 1.0 1.0 0.0 # 3 c
v 1.0 0.0 0.0 # 4 d
v 0.0 0.0 1.0 # 5 e
v 0.0 1.0 1.0 # 6 f
v 1.0 1.0 1.0 # 7 g
v 1.0 0.0 1.0 # 8 h
# Normal vectors
# One for each face. Shared by all vertices in that face.
vn 1.0 0.0 0.0 # 1 cghd
vn -1.0 0.0 0.0 # 2 aefb
vn 0.0 1.0 0.0 # 3 gcbf
vn 0.0 -1.0 0.0 # 4 dhea
vn 0.0 0.0 1.0 # 5 hgfe
vn 0.0 0.0 -1.0 # 6 cdab
# Texture
# (u,v) coordinate into texture map image, ranging from 0.0 - 1.0.
# +---f---g---+---+
# | | 5 | | |
# f---e---h---g---+
# | 2 | 4 | 1 | | v
# b---a---d---c---+ |
# | | 6 | | | |
# +---b---c---+---+ +---- u
# | | 3 | | |
# +---f---g---+---+
vt 0.25 1.00 # 1 f(5) = f for face 5
vt 0.50 1.00 # 2 g(5)
vt 0 0.75 # 3 f(2)
vt 0.25 0.75 # 4 e(2,4,5)
vt 0.50 0.75 # 5 h(1,4,5)
vt 0.75 0.75 # 6 g(1)
vt 0 0.50 # 7 b(2)
vt 0.25 0.50 # 8 a(2,4,6)
vt 0.50 0.50 # 9 d(1,4,6)
vt 0.75 0.50 # 10 c(1)
vt 0.25 0.25 # 11 b(3,6)
vt 0.50 0.25 # 12 c(3,6)
vt 0.25 0 # 13 f(3)
vt 0.50 0 # 14 g(3)
# Define material for the following faces
usemtl texture
# Faces v/vt/vn
# 3-------2
# | - |
# | # | Each face = 2 triangles (ccw)
# | - | = 1-2-3 + 1-3-4
# 4-------1
# Face 1: cghd = cgh + chd
f 3/10/1 7/6/1 8/5/1
f 3/10/1 8/5/1 4/9/1
# Face 2: aefb = aef + afb
f 1/8/2 5/4/2 6/3/2
f 1/8/2 6/3/2 2/7/2
# Face 3: gcbf = gcb + gbf
f 7/14/3 3/12/3 2/11/3
f 7/14/3 2/11/3 6/13/3
# Face 4: dhea = dhe + dea
f 4/9/4 8/5/4 5/4/4
f 4/9/4 5/4/4 1/8/4
# Face 5: hgfe = hgf + hfe
f 8/5/5 7/2/5 6/1/5
f 8/5/5 6/1/5 5/4/5
# Face 6: cdab = cda + cab
f 3/12/6 4/9/6 1/8/6
f 3/12/6 1/8/6 2/11/6

View File

@ -0,0 +1,7 @@
newmtl texture
Ka 0.0 0.0 0.0
Kd 0.5 0.5 0.5
Ks 0.0 0.0 0.0
Ns 10.0
illum 2
map_Kd texture.png

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,6 @@
Model: mococo.obj
Author: pyr0xene
License: CC BY-NC 4.0 (https://creativecommons.org/licenses/by-nc/4.0/)
Source: https://sketchfab.com/3d-models/mococo-2c53699f4fe647beb52a7926821f5d9c
This model is used under the terms of the Creative Commons Attribution-NonCommercial license.

View File

@ -1,46 +0,0 @@
# Blender v2.76 (sub 0) OBJ File: ''
# www.blender.org
mtllib cube.mtl
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 1.000000 0.333333
vt 1.000000 0.666667
vt 0.666667 0.666667
vt 0.666667 0.333333
vt 0.666667 0.000000
vt 0.000000 0.333333
vt 0.000000 0.000000
vt 0.333333 0.000000
vt 0.333333 1.000000
vt 0.000000 1.000000
vt 0.000000 0.666667
vt 0.333333 0.333333
vt 0.333333 0.666667
vt 1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -0.000000 0.000000 1.000000
vn -1.000000 -0.000000 -0.000000
vn 0.000000 0.000000 -1.000000
usemtl Material
s off
f 2/1/1 3/2/1 4/3/1
f 8/1/2 7/4/2 6/5/2
f 5/6/3 6/7/3 2/8/3
f 6/8/4 7/5/4 3/4/4
f 3/9/5 7/10/5 8/11/5
f 1/12/6 4/13/6 8/11/6
f 1/4/1 2/1/1 4/3/1
f 5/14/2 8/1/2 6/5/2
f 1/12/3 5/6/3 2/8/3
f 2/12/4 6/8/4 3/4/4
f 4/13/5 3/9/5 8/11/5
f 5/6/6 1/12/6 8/11/6

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@ -0,0 +1,7 @@
newmtl texture
Ka 0.0 0.0 0.0
Kd 0.5 0.5 0.5
Ks 0.0 0.0 0.0
Ns 10.0
illum 2
map_Kd texture.png

View File

@ -0,0 +1,15 @@
# Blender v2.57 (sub 0) OBJ File: ''
# www.blender.org
mtllib quad.mtl
o Cube_Cube.001
v -1.000000 1.000000 0.000000
v 1.000000 1.000000 0.000000
v -1.000000 -1.000000 0.000000
v 1.000000 -1.000000 0.000000
vt 1.000000 1.000000
vt 0.000000 1.000000
vt 0.000000 0.000000
vt 1.000000 0.000000
s off
f 4/4 3/3 1/2
f 2/1 4/4 1/2

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB