Skip to content

Instantly share code, notes, and snippets.

@cwfitzgerald
Last active September 15, 2018 01:49
Show Gist options
  • Save cwfitzgerald/91f17238836fbdd62e61bf301f3894e4 to your computer and use it in GitHub Desktop.
Save cwfitzgerald/91f17238836fbdd62e61bf301f3894e4 to your computer and use it in GitHub Desktop.
/*
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