Single file, header-only .OBJ mesh loader with zero dependancies
Joel Davis (joeld42@gmail.com) Twitter: @joeld42
Tapnik Software (www.tapnik.com)
Note: for backstory about this library read this blog post: http://www.tapnik.com/blog/tk-objfile.html
Features:
Limitations:
This file parses an OBJ with a "triangle soup" style API.
To use, simply include "tk_objfile.h". Exactly one of the including C or CPP files needs to define TK_OBJFILE_IMPLEMENTATION before including to generate the implementation. For example:
#define TK_OBJFILE_IMPLEMENTATION #include "tk_objfile.h"
Basic usage is to create a TK_ObjDelegate with the callbacks:
// Called once for each material that has one or more triangles using it. void (*material)( const char *mtlName, size_t numTriangles, void *userData ); // Called once for each triangle using the material. void (*triangle)( TK_TriangleVert a, TK_TriangleVert b, TK_TriangleVert c, void *userData ); // Will report errors from parsing. void (*error)( size_t lineNumber, const char *message, void *userData );
All the callbacks are optional. All callbacks pass in a void *userData from the objDelegate for a convienent way to pass in some context.
MEMORY: The parser doesn't allocate any memory. Instead, you must pass in a "scratchMemory" buffer in the objDelegate that is large enough to hold the results from the parsing and a small amount of working memory. There are two approaches to this:
First, you can call TK_ParseObj with 0 for scratchMemSize, and it will only do a pre-parse and fill in scratchMemSize with how much space it needs. Then, allocate at least that much space in scratchMem and call TK_ParseObj again and it will do the actual parse.
Alternatively, if you know how big the objects you'll be parsing is, or if you happen to have a large scratch buffer on hand, then you can just pass that in in the first place. This saves one redundant pre-parse, but it doesn't really save much time, but it might be simpler.
Here's a example of how it might be called:
// Create delegate and assign callbacks TK_ObjDelegate objDelegate = {}; objDelegate.error = myCallbackErrorMessage; objDelegate.material = myCallbackSwitchMaterial; objDelegate.triangle = myCallbackProcessTriangle; // Read the .OBJ file from disk size_t objFileSize = 0; void *objFileData = readEntireFile( "cube1.obj", &objFileSize ); // Prepass to determine memory requirements objDelegate.scratchMemSize = 0; TK_ParseObj( objFileData, objFileSize, &objDelegate ); // Allocate scratch memory objDelegate.scratchMem = malloc( objDelegate.scratchMemSize ); // Parse again with memory. This will call material() and // triangle() callbacks TK_ParseObj( objFileData, objFileSize, &objDelegate );
The "triangle soup" style throws away the index vertex info. Originally I included an API to preserve the indexed data, but since it's indexed differently than OpenGL/DX you probably have to reindex it anyways, so I removed it to keep things simple. In a real world pipeline you might want to run it through a real triangle stripper or something.
I still want to add a simple wrapper API that uses cstdlib and just loads the obj with a single call.
example_bbox.cpp - Prints the bounding box for an obj file. This is a good starting point to see how to use it.
objviewer - Object viewer using IMGUI/glfw. This is a pretty craptastic viewer, it needs a lot of work, but it's a start. Handles multiple materials, will tint each material a different color. When loading objects, if there is a .png image with the same name as the material name, it will load that as a texture (see hugzilla.obj for an example)
If you would like to contribute, here's some things that would be helpful:
smaller improvements:
bigger future features:
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4