Skip to content

Commit

Permalink
Functionality for loading *.obj file from SD card.
Browse files Browse the repository at this point in the history
  • Loading branch information
nthnn committed Aug 13, 2024
1 parent aa96d70 commit b7a793a
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 1 deletion.
132 changes: 131 additions & 1 deletion src/goblin3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include <goblin3d.h>
#include <math.h>
#include <SD.h>

bool goblin3d_init(goblin3d_obj_t* obj, uint32_t point_count, uint32_t edge_count) {
size_t fsize = sizeof(float);
Expand Down Expand Up @@ -94,6 +95,16 @@ bool goblin3d_init(goblin3d_obj_t* obj, uint32_t point_count, uint32_t edge_coun
return true;
}

void goblin3d_init_empty(goblin3d_obj_t* obj) {
obj->point_count = 0;
obj->edge_count = 0;

obj->points = NULL;
obj->orig_points = NULL;
obj->rotated_points = NULL;
obj->edges = NULL;
}

void goblin3d_free(goblin3d_obj_t* obj) {
for(uint32_t i = 0; i < obj->point_count; i++) {
if(obj->points[i])
Expand Down Expand Up @@ -136,7 +147,7 @@ void goblin3d_precalculate(goblin3d_obj_t* obj) {
float sinY = sin(radY);
float sinZ = sin(radZ);

for(uint32_t i=0; i<obj->point_count; i++) {
for(uint32_t i = 0; i < obj->point_count; i++) {
float x = obj->orig_points[i][0];
float y = obj->orig_points[i][1];
float z = obj->orig_points[i][2];
Expand Down Expand Up @@ -173,4 +184,123 @@ void goblin3d_render(goblin3d_obj_t* obj, goblin3d_obj_draw_fn draw) {
obj->points[end][1]
);
}
}

bool goblin3d_add_point(goblin3d_obj_t* obj, float x, float y, float z) {
obj->point_count++;

obj->orig_points = (float**) realloc(obj->orig_points, obj->point_count * sizeof(float*));
if(obj->orig_points == NULL)
return false;

obj->rotated_points = (float**) realloc(obj->rotated_points, obj->point_count * sizeof(float*));
if(obj->rotated_points == NULL)
return false;

obj->points = (float**) realloc(obj->points, obj->point_count * sizeof(float*));
if(obj->points == NULL)
return false;

obj->orig_points[obj->point_count - 1] = (float*) malloc(3 * sizeof(float));
if(obj->orig_points == NULL)
return false;

obj->rotated_points[obj->point_count - 1] = (float*) malloc(3 * sizeof(float));
if(obj->rotated_points == NULL)
return false;

obj->points[obj->point_count - 1] = (float*) malloc(3 * sizeof(float));
if(obj->points == NULL)
return false;

obj->orig_points[obj->point_count - 1][0] = x;
obj->orig_points[obj->point_count - 1][1] = y;
obj->orig_points[obj->point_count - 1][2] = z;

return true;
}

bool goblin3d_edge_exists(goblin3d_obj_t* obj, uint32_t v1, uint32_t v2) {
for(int i = 0; i < obj->edge_count; ++i) {
uint32_t existing_v1 = obj->edges[i][0],
existing_v2 = obj->edges[i][1];
if((existing_v1 == v1 && existing_v2 == v2) ||
(existing_v1 == v2 && existing_v2 == v1))
return true;
}

return false;
}

bool goblin3d_add_edge(goblin3d_obj_t* obj, uint32_t v1, uint32_t v2) {
if(goblin3d_edge_exists(obj, v1, v2))
return true;

obj->edge_count++;
obj->edges = (uint32_t**) realloc(obj->edges, obj->edge_count * sizeof(uint32_t*));
if(obj->edges == NULL)
return false;

obj->edges[obj->edge_count - 1] = (uint32_t*)malloc(2 * sizeof(uint32_t));
obj->edges[obj->edge_count - 1][0] = v1;
obj->edges[obj->edge_count - 1][1] = v2;

return true;
}

bool goblin3d_parse_obj_file(const char* filename, goblin3d_obj_t* obj) {
File file = SD.open(filename);
if(!file)
return false;
goblin3d_init_empty(obj);

String line = "";
while(file.available()) {
char c = file.read();

if(c == '\n' || c == '\r') {
if(line.startsWith("v ")) {
float x, y, z;

sscanf(line.c_str() + 2, "%f %f %f", &x, &y, &z);
if (!goblin3d_add_point(obj, x, y, z)) {
file.close();
return false;
}
}
else if(line.startsWith("f ")) {
uint32_t vertex_indices[4];
int count = sscanf(
line.c_str() + 2,
"%u %u %u %u",
&vertex_indices[0],
&vertex_indices[1],
&vertex_indices[2],
&vertex_indices[3]
);

if(count == 3) {
goblin3d_add_edge(obj, vertex_indices[0] - 1, vertex_indices[1] - 1);
goblin3d_add_edge(obj, vertex_indices[1] - 1, vertex_indices[2] - 1);
goblin3d_add_edge(obj, vertex_indices[2] - 1, vertex_indices[0] - 1);
}
else if(count == 4) {
goblin3d_add_edge(obj, vertex_indices[0] - 1, vertex_indices[1] - 1);
goblin3d_add_edge(obj, vertex_indices[1] - 1, vertex_indices[2] - 1);
goblin3d_add_edge(obj, vertex_indices[2] - 1, vertex_indices[3] - 1);
goblin3d_add_edge(obj, vertex_indices[3] - 1, vertex_indices[0] - 1);
}
}
else if(line[0] == 'm' || line[0] == 'o' ||
line[0] == '#' || line[0] == 'g' ||
line[0] == 's' || line[0] == 'u' ||
line[0] == 'n');

line = "";
}
else line += c;
}

file.close();
return true;
}
74 changes: 74 additions & 0 deletions src/goblin3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,18 @@ typedef void (*goblin3d_obj_draw_fn)(uint16_t x1, uint16_t y1, uint16_t x2, uint
*/
bool goblin3d_init(goblin3d_obj_t* obj, uint32_t point_count, uint32_t edge_count);

/**
* @brief Initializes an empty Goblin3D object.
*
* This function sets up an empty Goblin3D object by initializing its point and
* edge counts to zero and setting all point and edge pointers to `NULL`. This
* function is useful for setting up a new object before adding points and edges
* to it.
*
* @param obj A pointer to the Goblin3D object to initialize.
*/
void goblin3d_init_empty(goblin3d_obj_t* obj);

/**
* @brief Frees the memory associated with a 3D object structure.
*
Expand Down Expand Up @@ -208,4 +220,66 @@ void goblin3d_precalculate(goblin3d_obj_t* obj);
*/
void goblin3d_render(goblin3d_obj_t* obj, goblin3d_obj_draw_fn draw);

/**
* @brief Adds a 3D point to a Goblin3D object.
*
* This function adds a new 3D point to the Goblin3D object by reallocating memory
* for the points and storing the coordinates. The new point is added to both the
* original and rotated points arrays.
*
* @param obj A pointer to the Goblin3D object.
* @param x The x-coordinate of the point.
* @param y The y-coordinate of the point.
* @param z The z-coordinate of the point.
* @return `true` if the point was added successfully, `false` if a memory allocation
* error occurred.
*/
bool goblin3d_add_point(goblin3d_obj_t* obj, float x, float y, float z);

/**
* @brief Checks if an edge exists between two vertices in a Goblin3D object.
*
* This function checks whether an edge exists between two specified vertices
* (identified by their indices) in the Goblin3D object's edges array. An edge
* is considered to exist if there is an edge in the array that connects the
* two vertices in either order.
*
* @param obj A pointer to the Goblin3D object.
* @param v1 The index of the first vertex.
* @param v2 The index of the second vertex.
* @return `true` if the edge exists, `false` otherwise.
*/
bool goblin3d_edge_exists(goblin3d_obj_t* obj, uint32_t v1, uint32_t v2);

/**
* @brief Adds an edge between two vertices in a Goblin3D object.
*
* This function adds a new edge between two vertices (identified by their indices)
* in the Goblin3D object. If the edge already exists, the function returns `true`
* without adding a duplicate edge. If the edge does not exist, it is added to the
* edges array.
*
* @param obj A pointer to the Goblin3D object.
* @param v1 The index of the first vertex.
* @param v2 The index of the second vertex.
* @return `true` if the edge was added successfully, `false` if a memory allocation
* error occurred.
*/
bool goblin3d_add_edge(goblin3d_obj_t* obj, uint32_t v1, uint32_t v2);

/**
* @brief Parses an OBJ file to construct a Goblin3D object.
*
* This function reads a Wavefront OBJ file and constructs a Goblin3D object from it.
* The function initializes the object, reads vertices and faces from the file, and
* adds the corresponding points and edges to the Goblin3D object. The OBJ file should
* be formatted according to the standard OBJ file format specification.
*
* @param filename The path to the OBJ file to parse.
* @param obj A pointer to the Goblin3D object to populate.
* @return `true` if the OBJ file was successfully parsed and the object constructed,
* `false` if an error occurred (e.g., file not found, memory allocation failure).
*/
bool goblin3d_parse_obj_file(const char* filename, goblin3d_obj_t* obj);

#endif /* GOBLIN3D_H */

0 comments on commit b7a793a

Please sign in to comment.