Last active
September 15, 2018 01:49
-
-
Save cwfitzgerald/91f17238836fbdd62e61bf301f3894e4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Loading C:\Users\connor\Downloads\models\lucy.obj. | |
Duration: 1948.9ms | |
Verts: 14027872 | |
Faces: 28055728 | |
Verts/s: 7197976.0 | |
Faces/s: 14395943.9 | |
MB/s: 605.4 | |
*/ | |
#include <chrono> | |
#include <fstream> | |
#include <iomanip> | |
#include <array> | |
#include <iostream> | |
#include <tuple> | |
#include <utility> | |
#include <vector> | |
#define WIN32_LEAN_AND_MEAN | |
#include <Windows.h> | |
std::pair<char const*, std::size_t> open_file(std::string const& filename) { | |
auto const file_handle = CreateFileA(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); // Leaked it | |
auto const mapping_handle = CreateFileMappingA(file_handle, nullptr, PAGE_READONLY, 0, 0, nullptr); // Leaked it | |
void* const ptr = MapViewOfFile(mapping_handle, FILE_MAP_READ, 0, 0, 0); | |
MEMORY_BASIC_INFORMATION info; | |
VirtualQuery(ptr, &info, sizeof(info)); | |
return std::make_pair(static_cast<char const *>(ptr), info.RegionSize); | |
} | |
bool is_digit(char const c) { | |
return ('0' <= c && c <= '9'); | |
} | |
bool is_number(char c) { | |
return is_digit(c) || c == '-' || c == '.'; | |
} | |
namespace custom { | |
float strtof(char const * const input, char ** const end) { | |
constexpr std::array<double, 8> inverted_powers = { | |
0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001 | |
}; | |
std::size_t index = 0; | |
// skip whitespace | |
while (!is_number(input[index]) && input[index] != '\0') { | |
index += 1; | |
} | |
bool negation = false; | |
double number = 0.0; | |
while (input[index] != '\0') { | |
if (input[index] == '-') { | |
negation = true; | |
} | |
else if (is_digit(input[index])) { | |
number = (number * 10) + (input[index] - '0'); | |
} | |
else { | |
break; | |
} | |
index += 1; | |
} | |
std::uint32_t decimal_exponent = 0; | |
if (input[index] == '.') { | |
index += 1; | |
while (input[index] != '\0') { | |
if (is_digit(input[index])) { | |
number += (input[index] - '0') * inverted_powers[decimal_exponent++]; | |
if (decimal_exponent == 8) { | |
break; | |
} | |
} | |
else { | |
break; | |
} | |
index += 1; | |
} | |
} | |
// skip excess numbers | |
while (is_number(input[index]) && input[index] != '\0') { | |
index += 1; | |
} | |
*end = const_cast<char*>(input + index); | |
return static_cast<float>(number); | |
} | |
long strtol(char const * const input, char ** const end) { | |
std::size_t index = 0; | |
// skip whitespace | |
while (!is_number(input[index]) && input[index] != '\0') { | |
index += 1; | |
} | |
bool negation = false; | |
long number = 0; | |
while (input[index] != '\0') { | |
if (input[index] == '-') { | |
negation = true; | |
} | |
else if (is_digit(input[index])) { | |
number = (number * 10) + (input[index] - '0'); | |
} | |
else { | |
break; | |
} | |
index += 1; | |
} | |
*end = const_cast<char*>(input + index); | |
return number; | |
} | |
} | |
struct Position { | |
float x; | |
float y; | |
float z; | |
}; | |
struct Color { | |
float r; | |
float g; | |
float b; | |
}; | |
struct Vertex { | |
Position pos; | |
Color color; | |
}; | |
struct ParsedObj { | |
std::vector<Position> vertices; | |
std::vector<int32_t> indices; | |
}; | |
ParsedObj parse_obj(const char* const input, std::size_t const size) { | |
ParsedObj ret; | |
std::size_t index = 0; | |
while(index != size) { | |
// Index points to beginning of line | |
if (input[index] == 'v') { | |
// skip space | |
index += 2; | |
// parse x | |
char * out_ptr; | |
float const x = custom::strtof(input + index, &out_ptr); | |
index = out_ptr - input; | |
// points to space | |
index += 1; | |
// parse y | |
float const y = custom::strtof(input + index, &out_ptr); | |
index = out_ptr - input; | |
// points to space | |
index += 1; | |
// parse z | |
float const z = custom::strtof(input + index, &out_ptr); | |
index = out_ptr - input; | |
if (input[index] == '\r') { | |
index += 1; | |
} | |
ret.vertices.emplace_back(Position{ x, y, z }); | |
} | |
else if (input[index] == 'f') { | |
// skip space | |
index += 2; | |
// parse 1 | |
char * out_ptr; | |
int32_t const x = custom::strtol(input + index, &out_ptr); | |
index = out_ptr - input; | |
// points to space | |
index += 1; | |
// parse 2 | |
int32_t const y = custom::strtol(input + index, &out_ptr); | |
index = out_ptr - input; | |
// points to space | |
index += 1; | |
// parse 3 | |
int32_t const z = custom::strtol(input + index, &out_ptr); | |
index = out_ptr - input; | |
if (input[index] == '\r') { | |
index += 1; | |
} | |
ret.indices.emplace_back(x); | |
ret.indices.emplace_back(y); | |
ret.indices.emplace_back(z); | |
} | |
else { | |
while (index != size - 1 && input[index] != '\n') index++; | |
} | |
// All paths return with index pointing to the newline | |
index += 1; | |
} | |
return ret; | |
} | |
int main(int argc, char** argv) { | |
if (argc < 2) { | |
std::cerr << "Must pass filename on command line.\n"; | |
exit(1); | |
} | |
std::cout << "Loading " << argv[1] << ".\n"; | |
auto const start = std::chrono::high_resolution_clock::now(); | |
const char * base_ptr; | |
std::size_t size; | |
std::tie(base_ptr, size) = open_file(argv[1]); | |
auto result = parse_obj(base_ptr, size); | |
auto const end = std::chrono::high_resolution_clock::now(); | |
auto duration = end - start; | |
double const milliseconds = duration.count() / 1'000'000.0; | |
double const seconds = duration.count() / 1'000'000'000.0; | |
std::size_t const verts = result.vertices.size(); | |
std::size_t const faces = result.indices.size() / 3; | |
double const megabytes = size / static_cast<float>(1024 * 1024); | |
std::cout << " Duration: " << std::fixed << std::setprecision(1) << milliseconds << "ms\n"; | |
std::cout << " Verts: " << verts << "\n"; | |
std::cout << " Faces: " << faces << "\n"; | |
std::cout << " Verts/s: " << verts / seconds << "\n"; | |
std::cout << " Faces/s: " << faces / seconds << "\n"; | |
std::cout << " MB/s: " << megabytes / seconds << "\n"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment