Added comments
This commit is contained in:
parent
509e94ac58
commit
e58ad18fb1
5 changed files with 82 additions and 14 deletions
|
@ -1,14 +1,20 @@
|
|||
// not good at using namespaces, bear with me
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
// struct to hold vertex position
|
||||
struct Vertex {
|
||||
float pos[3];
|
||||
};
|
||||
|
||||
// struct to hold normal vectors
|
||||
struct Normal {
|
||||
float dir[3];
|
||||
};
|
||||
|
||||
// struct to hold material information
|
||||
struct Material {
|
||||
int idx;
|
||||
string name;
|
||||
|
@ -17,12 +23,15 @@ struct Material {
|
|||
float diffuse[4];
|
||||
};
|
||||
|
||||
// meta struct for each individual face, pointers to its set of
|
||||
// vertices, normals and material structs
|
||||
struct Face {
|
||||
vector<Vertex*> vertices;
|
||||
vector<Normal*> normals;
|
||||
Material* mtl;
|
||||
};
|
||||
|
||||
// class to load and handle .obj and .mtl parsing and face data construction
|
||||
class ObjectLoader
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -10,26 +10,28 @@ public:
|
|||
OPGLWidget(QWidget *parent) : QOpenGLWidget(parent) {}
|
||||
ObjectLoader obj;
|
||||
public slots:
|
||||
void paintGL();
|
||||
void update_camera();
|
||||
void paintGL(); // for repaint loop
|
||||
void update_camera(); // for mouse movement
|
||||
protected:
|
||||
void initializeGL();
|
||||
void resizeGL(int w, int h);
|
||||
void reorient();
|
||||
|
||||
// camera controls
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
void keyReleaseEvent(QKeyEvent *event);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void mouseReleaseEvent(QMouseEvent *event);
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
|
||||
int mtl_idx = -1;
|
||||
float loc[3] = {0, 0, 10};
|
||||
float f[3] = {0, 0, -1};
|
||||
float up[3] = {0, 1, 0};
|
||||
float right[3] = {1, 0, 0};
|
||||
float vel[3] = {0, 0, 0};
|
||||
float speed = 0;
|
||||
bool key_states[6] = {false, false, false, false, false, false};
|
||||
float mouse_loc_old[2];
|
||||
// init values
|
||||
int mtl_idx = -1; // index to store current material to use
|
||||
float loc[3] = {0, 0, 10}; // initial camera position
|
||||
float f[3] = {0, 0, -1}; // initial camera direction
|
||||
float up[3] = {0, 1, 0}; // initial camera up vector
|
||||
float right[3] = {1, 0, 0}; // initial camera right vector
|
||||
float vel[3] = {0, 0, 0}; // initial camera velocity
|
||||
float speed = 0; // placeholder init for abs speed (for limit and slowing mostly)
|
||||
bool key_states[6] = {false, false, false, false, false, false}; // camera control states
|
||||
float mouse_loc_old[2]; // for calculating camera direction changes with mouse movement
|
||||
};
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
#include <QCommandLineParser>
|
||||
#include <QCommandLineOption>
|
||||
|
||||
// main loop
|
||||
int main(int argc, char **argv) {
|
||||
QApplication app(argc, argv);
|
||||
QCommandLineParser parser;
|
||||
// pass in files as -m and -o
|
||||
QCommandLineOption mtl_filepath_opt({"m", "material"}, "Material file path, required", "path");
|
||||
QCommandLineOption obj_filepath_opt({"o", "object"}, "Object file path, required", "path");
|
||||
parser.addHelpOption();
|
||||
|
@ -19,16 +21,21 @@ int main(int argc, char **argv) {
|
|||
if (mtl_filepath.isEmpty() || obj_filepath.isEmpty()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
QMainWindow w;
|
||||
Ui::MainWindow ui;
|
||||
ui.setupUi(&w);
|
||||
|
||||
// parse obj and mtl files
|
||||
ui.openGLWidget->obj.load_mtl(mtl_filepath.toStdString());
|
||||
ui.openGLWidget->obj.load_obj(obj_filepath.toStdString());
|
||||
|
||||
// timers for drawing and movement loops
|
||||
QTimer timer_draw;
|
||||
QTimer timer_cam;
|
||||
w.connect(&timer_draw, SIGNAL(timeout()), ui.openGLWidget, SLOT(paintGL()));
|
||||
w.connect(&timer_cam, SIGNAL(timeout()), ui.openGLWidget, SLOT(update_camera()));
|
||||
// update every 16ms
|
||||
timer_draw.start(16);
|
||||
timer_cam.start(16);
|
||||
w.show();
|
||||
|
|
28
src/obj.cpp
28
src/obj.cpp
|
@ -5,11 +5,16 @@
|
|||
#include <cstring>
|
||||
#include <regex>
|
||||
|
||||
// .mtl file load and parse
|
||||
void ObjectLoader::load_mtl(string filename) {
|
||||
string tmp;
|
||||
ifstream f(filename);
|
||||
int mtl_idx = -1;
|
||||
ifstream f(filename); // open file
|
||||
int mtl_idx = -1; // init index outside of valid range
|
||||
while (getline(f, tmp)) {
|
||||
// if line defines a new material
|
||||
// create new and set its name
|
||||
// following lines will define ambient, spec, diffuse info for
|
||||
// the newly defined material
|
||||
if (tmp.rfind("newmtl", 0) == 0) {
|
||||
mtl_idx += 1;
|
||||
mtls.push_back(*(new Material));
|
||||
|
@ -29,23 +34,30 @@ void ObjectLoader::load_mtl(string filename) {
|
|||
default:
|
||||
continue;
|
||||
};
|
||||
// parse syntax
|
||||
// eg; Kd 0.2 0.2 0.2
|
||||
// delim by space, split and parse value
|
||||
char delim = ' ';
|
||||
char *token = strtok(const_cast<char*>(tmp.c_str()), &delim);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
token = strtok(NULL, &delim);
|
||||
target_list[i] = atof(token);
|
||||
};
|
||||
// set alpha val since blender doesn't output it
|
||||
target_list[3] = 1.0f;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// .obj file load and parsing
|
||||
// only supports single object files
|
||||
void ObjectLoader::load_obj(string filename) {
|
||||
string tmp;
|
||||
ifstream f(filename);
|
||||
while (getline(f, tmp)) {
|
||||
Material* mtl_ptr;
|
||||
if (tmp[0] == 'v') {
|
||||
// if vertex (v) or vertex normal (vn), create new vertex struct
|
||||
float* target_list;
|
||||
switch (tmp[1]) {
|
||||
case ' ':
|
||||
|
@ -59,6 +71,11 @@ void ObjectLoader::load_obj(string filename) {
|
|||
default:
|
||||
continue;
|
||||
};
|
||||
// same parsing as material values above
|
||||
// something breaks here somehow on first run i think
|
||||
// no clue if its pointer wierdness or something with
|
||||
// the files but vector floats get borked
|
||||
// works perfectly fine on next runs so... eh?
|
||||
char delim = ' ';
|
||||
char *token = strtok(const_cast<char*>(tmp.c_str()), &delim);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
|
@ -67,8 +84,14 @@ void ObjectLoader::load_obj(string filename) {
|
|||
};
|
||||
|
||||
} else if (tmp.rfind("usemtl", 0) == 0) {
|
||||
// if line declares material scope, point the pointer to said material
|
||||
mtl_ptr = get_mtl_ptr(tmp.substr(tmp.find(' ') + 1));
|
||||
} else if (tmp[0] == 'f') {
|
||||
// face declared as set of v/vt/vn indexes
|
||||
// currently ignoring vt and only using files without any vt exported
|
||||
// (like generic meshes with materials)
|
||||
// also only handles triangle mesh objects
|
||||
// assign it a metal and its corresponding vertexes and normals
|
||||
faces.push_back(*(new Face));
|
||||
faces.back().mtl = mtl_ptr;
|
||||
regex re("f (\\d*)//(\\d*) (\\d*)//(\\d*) (\\d*)//(\\d*)");
|
||||
|
@ -85,6 +108,7 @@ void ObjectLoader::load_obj(string filename) {
|
|||
};
|
||||
};
|
||||
|
||||
// just finds the pointer to the given material from its string
|
||||
Material* ObjectLoader::get_mtl_ptr(string mtl_name) {
|
||||
for (size_t i = 0; i < mtls.size(); i++) {
|
||||
if (mtls[i].name == mtl_name) {
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
#include <math.h>
|
||||
#include <QKeyEvent>
|
||||
|
||||
// probably should have learned OpenGL and rendering
|
||||
// first, not even going to pretend to know what the first half
|
||||
// does
|
||||
void OPGLWidget::initializeGL() {
|
||||
glClearDepth(1.0f);
|
||||
glDepthFunc(GL_LESS);
|
||||
|
@ -14,6 +17,7 @@ void OPGLWidget::initializeGL() {
|
|||
glMatrixMode(GL_MODELVIEW);
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_LIGHT0);
|
||||
// values here largely just copied from default light object in blender
|
||||
GLfloat light_ambient[] = {0.0, 0.0, 0.0, 1.0};
|
||||
GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0};
|
||||
GLfloat light_specular[] = {0.0, 0.5, 0.5, 0.2};
|
||||
|
@ -25,13 +29,18 @@ void OPGLWidget::initializeGL() {
|
|||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
// paint loop
|
||||
void OPGLWidget::paintGL() {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glLoadIdentity();
|
||||
reorient();
|
||||
reorient(); // implementation of gluPerspective to shift camera perspective
|
||||
// mostly just because I could not figure out how to get GLU included properly
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glPolygonMode(GL_FRONT, GL_FILL);
|
||||
glBegin(GL_TRIANGLES);
|
||||
// for each face, check if its material is different from the one
|
||||
// currently selected in mtl_idx. if different, populate new values and move idx
|
||||
// then draw each vertex and normal
|
||||
for (size_t i = 0; i < obj.faces.size(); i++) {
|
||||
Material* mtl_ptr = obj.faces[i].mtl;
|
||||
if (mtl_idx != mtl_ptr->idx) {
|
||||
|
@ -51,6 +60,7 @@ void OPGLWidget::paintGL() {
|
|||
update();
|
||||
}
|
||||
|
||||
// cursed implementation of gluPerscpective here: https://registry.khronos.org/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml
|
||||
void OPGLWidget::reorient() {
|
||||
GLfloat s[] = {-f[2], 0, f[0]};
|
||||
float s_mag = pow(pow(s[0], 2) + pow(s[1], 2) + pow(s[2], 2), 0.5);
|
||||
|
@ -62,6 +72,7 @@ void OPGLWidget::reorient() {
|
|||
glTranslatef(-loc[0], -loc[1], -loc[2]);
|
||||
}
|
||||
|
||||
// window resize
|
||||
void OPGLWidget::resizeGL(int w, int h) {
|
||||
glViewport(0, 0, w, h);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
|
@ -73,10 +84,13 @@ void OPGLWidget::resizeGL(int w, int h) {
|
|||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
// camera update, movement simulation
|
||||
void OPGLWidget::update_camera() {
|
||||
// update location in direction of velocity by 1/100 of speed each tick
|
||||
for (int i = 0; i < 3; i++) {
|
||||
loc[i] += vel[i] * speed/100.0f;
|
||||
};
|
||||
// cursed, but its here, update velocity by corresponding key
|
||||
if (key_states[0]) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
vel[i] += f[i];
|
||||
|
@ -108,11 +122,14 @@ void OPGLWidget::update_camera() {
|
|||
}
|
||||
};
|
||||
speed = pow(pow(vel[0], 2) + pow(vel[1], 2) + pow(vel[2], 2), 0.5);
|
||||
// speed limit, update vel if over
|
||||
if (speed > 2) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
vel[i] = vel[i] / speed;
|
||||
}
|
||||
}
|
||||
|
||||
// if no key pressed, decay speed until threshold then stop
|
||||
bool allFalse = true;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (key_states[i]) {
|
||||
|
@ -131,6 +148,7 @@ void OPGLWidget::update_camera() {
|
|||
}
|
||||
}
|
||||
|
||||
// key mappings
|
||||
void OPGLWidget::keyPressEvent(QKeyEvent *event) {
|
||||
switch (event -> key()) {
|
||||
case Qt::Key_W:
|
||||
|
@ -177,29 +195,37 @@ void OPGLWidget::keyReleaseEvent(QKeyEvent *event) {
|
|||
};
|
||||
}
|
||||
|
||||
// camera panning only happens on drag, also makes it so I don't
|
||||
// have to bother with mouse capture and other wierdness from i3 tiling
|
||||
void OPGLWidget::mousePressEvent(QMouseEvent *event) {
|
||||
setMouseTracking(true);
|
||||
mouse_loc_old[0] = event -> x();
|
||||
mouse_loc_old[1] = event -> y();
|
||||
}
|
||||
|
||||
// stop tracking on release
|
||||
void OPGLWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
setMouseTracking(false);
|
||||
mouse_loc_old[0] = event -> x();
|
||||
mouse_loc_old[1] = event -> y();
|
||||
}
|
||||
|
||||
// actual camera panning implementation
|
||||
void OPGLWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
// calc a delta movement from old, then new -> old
|
||||
float delta_x = event->x() - mouse_loc_old[0];
|
||||
float delta_y = event->y() - mouse_loc_old[1];
|
||||
mouse_loc_old[0] = event->x();
|
||||
mouse_loc_old[1] = event->y();
|
||||
// shift forward vector appropriately with movement
|
||||
for (int i = 0; i < 3; i++) {
|
||||
f[i] += right[i] * delta_x / 1000.0f;
|
||||
f[i] -= up[i] * delta_y / 1000.0f;
|
||||
}
|
||||
// since up is static, cross product to find right, which is simply:
|
||||
right[0] = -f[2];
|
||||
right[2] = f[0];
|
||||
// normalize forward and right
|
||||
float F_mag = pow(pow(f[0], 2) + pow(f[1], 2) + pow(f[2], 2), 0.5);
|
||||
float right_mag = pow(pow(right[0], 2) + pow(right[1], 2) + pow(right[2], 2), 0.5);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
|
|
Loading…
Reference in a new issue