浏览代码

Added comments and annotations to all of the engine

angel 7 年之前
父节点
当前提交
1bff4e98ce

+ 22 - 20
include/buffer.h

@@ -1,46 +1,48 @@
 #ifndef BUFFER_H
 #define BUFFER_H
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-10
+// PURPOSE      : Buffer template used as render targets for the software renderer
+// ===============================
 
 #include "SDL.h"
 #include <type_traits>
 
 //Templated struct to emulate GPU buffers such as 
-//the frame buffer and the ZBuffer along with others
+//the frame buffer and the ZBuffer 
 //Also keeps track of a bunch of useful data about itself
 template<class T>
 struct Buffer{
-        int mWidth;
-        int mHeight;
-        int mPixelCount;
-        int mPitch;
-        int mOrigin;
+        int mWidth, mHeight, mPixelCount, mPitch, mOrigin;
         T *buffer;
 
+        //The buffer is actually just a simple 1D array which we access using an equation
+        //Notice how it's not the usual (y*width + x) equation that you see for most quasi 2D arrays
+        //This is because the origin is at the lower left (instead of upper left) and y moves upwards
         T& operator()(size_t x, size_t y){
             return buffer[mOrigin + -y*mWidth + x];
         }
 
         Buffer(int w, int h, T * array) 
-        : mWidth(w), mHeight(h), mPixelCount(w*h),
-                mPitch(w*sizeof(T)),mOrigin(mHeight*mWidth - mWidth), buffer(array) 
-        {}
+        : mWidth(w), mHeight(h), mPixelCount(w*h), mPitch(w*sizeof(T)),
+          mOrigin(mHeight*mWidth - mWidth), buffer(array){}
 
-        ~Buffer(){
-                delete [] buffer;
-        };
+        ~Buffer(){delete [] buffer;}
         
         //Cannot use memset to clear a float since the binary
         //Representation is more complex. We just iterate through the whole
         //thing and explicitely set it to zero instead
         void clear(){
-                if(std::is_same<T,float>::value){
-                        for(int i = 0; i < mPixelCount;++i){
-                                buffer[i]  = 0.0f;
-                        }
-                }
-                else{
-                        memset(buffer,0xD, mPitch*mHeight);       
-                }
+            if(std::is_same<T,float>::value){
+				for(int i = 0; i < mPixelCount;++i){
+					buffer[i]  = 0.0f;
+				}
+            }
+			else{
+				//Set to a 15% white color to make it nicer looking.
+				memset(buffer,0xD, mPitch*mHeight);       
+			}
         }
 };
 

+ 22 - 7
include/camera.h

@@ -1,6 +1,20 @@
 #ifndef CAMERA_H
 #define CAMERA_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-10
+// PURPOSE      : To contain all camera and visibility related data. Also perform 
+//                view frustrum culling of a given AABB against the six planes of the
+//                camera frustrum. It allows for two types of movement, user controlled
+//                or orbiting mode. 
+// ===============================
+// SPECIAL NOTES: Some of the vectors saved in the camera are somewhat redundant, but
+// they are kept because I believe that recalculating them each frame is not really
+// worth it performance wise. I haven't profiled it however so who knows.
+// ===============================
+
+//Headers
 #include "matrix.h"
 #include "vector3D.h"
 #include "geometry.h"
@@ -8,15 +22,18 @@
 
 struct Camera{
     Camera();
-    
+
+    //Visibility and geometry member variables
+    Matrix4 viewMatrix;
+    Matrix4 projectionMatrix;
+    Frustrum cameraFrustrum{DisplayManager::SCREEN_ASPECT_RATIO};
+
+    //View frustrum culling
     bool checkVisibility(AABox *bounds);
 
     //Updates the camera matrices with the user input obtained in the input class
     void update(unsigned int deltaT);
-    void resetCamera();
-
-    Matrix4 viewMatrix;
-    Matrix4 projectionMatrix;
+    void resetCamera(); 
 
     //Position and direction of camera, used to build view matrix
     Vector3f position{0,0,8};
@@ -33,8 +50,6 @@ struct Camera{
     float camSpeed = 0.1f;
     float pitch    = 0;
     float yaw      = -90;
-
-    Frustrum cameraFrustrum{DisplayManager::SCREEN_ASPECT_RATIO};
 };
 
 #endif

+ 17 - 13
include/displayManager.h

@@ -1,17 +1,23 @@
 #ifndef DISPLAYMANAGER_H
 #define DISPLAYMANAGER_H
-
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-10
+// PURPOSE      : Manages the SDL screen itself and drawing to the display. 
+// ===============================
+// SPECIAL NOTES: Uses the old SDL1.2 backend because it's significantly faster
+// for  pure software rendering. Using the new one would incur a 6ms penalty even on 
+// empty frames. Probably has to do with sending data to the gpu every frame.
+// ===============================
+
+//Includes
+#include "SDL.h"
 #include "buffer.h"
 
-
-//Manages all low level display and window SDL stuff
-//Currently set up to work using SDL2 hardware rendering
-//I tested software rendering and although it was faster for simple color passes
-//It was slower when I tried to implement alpha blending, so I decided to revert
-//Back to the hardware accelerated backend.
 class DisplayManager{
-
     public:
+        //The screen size is fixed and set at compile time along with other important
+        //Display related values.
         const static int SCREEN_WIDTH  = 1280; //640 1280
         const static int SCREEN_HEIGHT = 720; //480 720
         const static int SCREEN_PITCH  = SCREEN_HEIGHT*sizeof(Uint32);
@@ -21,14 +27,11 @@ class DisplayManager{
         DisplayManager();
         ~DisplayManager();
 
-        //Initializes SDL context and creates window according to values above 
+        //Initializes SDL context and creates window according to above values
         bool startUp();
         void shutDown();
 
-        //Clear screens to draw color (Normally black)
-        void clear();
-
-        //Swaps the pixel buffer with the texture buffer and draws to screen
+        //Swaps the pixel buffer with the window surface buffer and draws to screen
         void swapBuffers(Buffer<Uint32> *pixelBuffer);
 
     private:
@@ -37,6 +40,7 @@ class DisplayManager{
         bool createWindow();
         bool createScreenSurface();
 
+        //Pointers to the SDL window and surface
         SDL_Surface  *mSurface;
         SDL_Window   *mWindow;
 };

+ 31 - 19
include/engine.h

@@ -1,34 +1,46 @@
 #ifndef ENGINE_H
 #define ENGINE_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-02
+// PURPOSE      : Application class containing all high level logic and init / shutdown
+//                routines for each major subsystem. The purpose of this program is to
+//                to build a functioning graphics engine without using libraries
+//                such as OpenGL or DirectX.
+// ===============================
+// SPECIAL NOTES: Built for educational purposes only.
+// ===============================
+
 //Headers
 #include "displayManager.h"
 #include "renderManager.h"
 #include "inputManager.h"
 #include "sceneManager.h"
 
-//Minimal graphics engine application
-class Engine{
-
-    public:
-        //Dummy constructors / Destructors
-        Engine();
-        ~Engine();
+//Very basic graphics engine application. 
+//In charge of initializing and closing down all manager-level classes in a safe way.
+class Engine
+{
+  public:
+    //Dummy constructors / Destructors
+    Engine();
+    ~Engine();
 
-        //I use these methods instead of constructors and destructors
-        //because I want to be able to control initialization order. 
-        //You'll see the same idea applied to all subsystem level classes.
-        bool startUp();
-        void shutDown();
+    //I use these methods instead of constructors and destructors
+    //because I want to be able to control initialization order.
+    //You'll see the same idea applied to all manager level classes.
+    bool startUp();
+    void shutDown();
 
-        //Contains all high level logic and the main application loop
-        void run();
+    //Contains all high level logic and the main application loop
+    void run();
 
-    private:
-        DisplayManager   gDisplayManager;
-        RenderManager    gRenderManager;
-        InputManager     gInputManager;
-        SceneManager     gSceneManager;
+  private:
+    DisplayManager gDisplayManager;
+    RenderManager gRenderManager;
+    InputManager gInputManager;
+    SceneManager gSceneManager;
 };
 
 #endif

+ 12 - 2
include/geometry.h

@@ -1,6 +1,15 @@
 #ifndef GEOMETRY_H
 #define GEOMETRY_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-19
+// PURPOSE      : This file contains all of the geometry classes. Mostly important for
+//                view frustrum culling since it contains the geometry for axis aligned
+//                bounding boxes, planes and frustrums.
+// ===============================
+
+//Headers
 #include "vector3D.h"
 #include "mesh.h"
 #include "matrix.h"
@@ -17,6 +26,8 @@ struct AABox{
     void update(const Matrix4 &modelMatrix);
 };
 
+//Only used in frustrum culling, a frustrum has 6 planes
+//Equation is Ax + By + Cz + D = 0 (or somthing)
 struct Plane{
     Vector3f normal;
     float D;
@@ -25,6 +36,7 @@ struct Plane{
     void setNormalAndPoint(const Vector3f &normal, const Vector3f &point);
 };
 
+//The shape of the camera view area
 class Frustrum{
     private:
     	enum {
@@ -40,6 +52,4 @@ class Frustrum{
         void updatePlanes(Matrix4 &viewMat, const Vector3f &cameraPos) ;
         bool checkIfInside(AABox *bounds);
 };
-
-
 #endif

+ 17 - 4
include/inputManager.h

@@ -1,28 +1,41 @@
 #ifndef INPUTMANAGER_H
 #define INPUTMANAGER_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-02
+// PURPOSE      : Managing user input either via keyboard, mouse movement, clicking, or
+//                even mouse wheel. It's currently mostly used for camera traversal,
+//                scene switching and exiting the program.
+// ===============================
+// SPECIAL NOTES: It works by directly calling functions that perform these actions,
+// that is it doesn't tell the camera to move by x amount on the next update cycle.
+// The input manager goes ahead and does just that. And withing the update calls of each
+// object that is affected it deals with the consequences of performing that action.
+// ===============================
+
 //Headers
 #include "sceneManager.h"
 #include "camera.h"
 #include "SDL.h"
 
 class InputManager{
-
     public:
         //Dummy constructors / Destructors
-        //Not necessary here, but follow the same format for consistency
+        //Not really necessary here, but follows the same format for consistency
         InputManager();
         ~InputManager();
 
         bool startUp(SceneManager &sceneManager);
         void shutDown();
 
-        //Processes all the SDL events that have ocurred in the given frame
+        //Processes all the SDL events that have ocurred in the past frame
         void processInput(bool &done, unsigned int deltaT);
     private:
-        
         SceneManager *sceneController;
         Camera *sceneCamera;
+        
+        //Where specific events are handled
         void handleEvent(SDL_Event * event, bool &done, unsigned int deltaT);
 };
 

+ 6 - 0
include/light.h

@@ -1,6 +1,12 @@
 #ifndef LIGHT_H
 #define LIGHT_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-08-03
+// PURPOSE      : POD struct containing the two vectors that describe a lightsource
+// ===============================
+
 #include "vector3D.h"
 
 struct BaseLight{

+ 19 - 4
include/matrix.h

@@ -1,6 +1,21 @@
 #ifndef MATRIX_H
 #define MATRIX_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-04
+// PURPOSE      : Perform matrix operations and linear algebra related operations.
+//                Also to have constructors to build the most common matrices used in 
+//                rendering.
+// ===============================
+// SPECIAL NOTES: All matrices are described as 4x4 matrices even if thery are supposed
+// to be only 3x3. This is because there is a special matmulDir function that performs
+// the equivalent multiplication that a 3x3 matrix would. Matrices are stored in memory
+// in row major order, but operations are done as if it was Column major. Exactly how
+// Opengl does. 
+// ===============================
+
+//Headers
 #include <array>
 #include "vector3D.h"
 
@@ -12,10 +27,10 @@ struct TransformParameters{
     Vector3f scaling;
 };
 
-//Matrices are stored in memory in row major order, but operations are done as if it was
-//Column major. 
 class Matrix4{
     public:
+        Matrix4(){};
+
         //Operators
         float& operator()(size_t y, size_t x){
             return mMatrix[y*4 + x];
@@ -35,8 +50,7 @@ class Matrix4{
         Matrix4 static fullRotMat(float alpha, float beta, float gamma);
         Matrix4 static scaleMat(float scaleX, float scaleY, float scaleZ);
         Matrix4 static translateMat(float dx, float dy, float dz);
-        Matrix4(){};
-
+        
         //Builds a matrix that scales, rotates and translates all at once
         Matrix4 static transformMatrix(TransformParameters transform);
 
@@ -47,6 +61,7 @@ class Matrix4{
         //defined as X[-1,1] Y[-1,1] Z[1,0] 
         Matrix4 static projectionMatrix(float fov, float AR, float near, float far);
 
+        //Tangent bitangent normal matrix used to get from world space to tangent space
         Matrix4 static TBNMatrix(const Vector3f &tangent, const Vector3f &biTangent, const Vector3f &normal);
 
         //Debug stuff

+ 12 - 1
include/mesh.h

@@ -1,11 +1,22 @@
 #ifndef MESH_H
 #define MESH_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-03
+// PURPOSE      : Container for all geometry information related to vertices and 
+//                faces. This information is what the renderer uses to build triangles.
+// ===============================
+// SPECIAL NOTES: Once again, this class uses a bunch of vectors instead of arrays and 
+// it's something I would change if I had more time. 
+// ===============================
+
+//Headers
 #include "vector3D.h"
 #include <vector>
 
 //Struct containing information relevant to the renderer about the vertices, normals and
-//texture coordinates of a model. Also keeps track of useful stuff for iterations.
+//texture coordinates of a model. Also keeps track of useful stuff for iterating.
 struct Mesh{
     //Per vertex values
     int numVertices = 0;

+ 15 - 1
include/model.h

@@ -1,6 +1,19 @@
 #ifndef MODEL_H
 #define MODEL_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-03
+// PURPOSE      : Container for all of the data realted to a model such as texture data,
+//                mesh data and even a model matrix for transformations.
+//                It has an update method that could be called based on physics updates
+//                but is not much more than a stub.
+// ===============================
+// SPECIAL NOTES: Should probably be rewritten to be a struct instead of having to use
+// all of these useless getters. This class is little more than a glorified container.
+// ===============================
+
+//Headers
 #include <string>
 #include "mesh.h"
 #include "geometry.h"
@@ -10,6 +23,8 @@
 
 class Model{
     public:
+        //On model creation all textures are loaded, the mesh is built and even an
+        //AABB is built.
         Model(std::string basePath,const TransformParameters &initParameters) : 
             mAlbedo(basePath + "_albedo.png", "RGB"),
             mNormal(basePath + "_normal.png", "XYZ"),
@@ -40,7 +55,6 @@ class Model{
         //Prints the mesh vertices for debugging
         void describeMesh();
     private:
-        
         Texture mAlbedo;
         Texture mNormal;
         Texture mAmbient;

+ 7 - 0
include/objParser.h

@@ -1,6 +1,13 @@
 #ifndef OBJPARSER_H
 #define OBJPARSER_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-14
+// PURPOSE      : Read .OBJ files and load the data into a mesh
+// ===============================
+
+//Headers
 #include <fstream>
 #include <sstream>
 #include "mesh.h"

+ 24 - 7
include/rasterizer.h

@@ -1,13 +1,29 @@
 #ifndef RASTERIZER_H
 #define RASTERIZER_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-03
+// PURPOSE      : To break down the vertex data into fragments. Determine which of those
+//                fragments are visible within the screen and within a given line/triangle.
+//                apply the fragment shader to each triangle and post process using gamma
+//                correction. Can rasterize points, lines and triangles.
+// ===============================
+// SPECIAL NOTES: Although line rasterization is possible the engine currently only supports
+// triangle rasterization through the higher level software rendering class. It's important
+// to also note that this rasterizer is nowhere close to optimized. On a future iteration,
+// it would an ideal candidate for a total makeover, reducing the coupling with other classes
+// and transforming the rasterizer pipeline from a float and scalar one to a fixed point 
+// and vectorized one. This would simplify the implementation of of many advanced features
+// such as mip-mapping, sub-pixel precision, gradient based shading and antialiasing which
+// are now very complicated to implement without it.
+// ===============================
+
+//Headers
 #include "SDL.h"
 #include "buffer.h"
 #include "vector3D.h"
 #include "shader.h"
-
-//Shorthand of repeated types.
-typedef std::array<float, 3> arr3f;
  
 //Takes in vertex data, rasterizes the surface and applies the fragment shader at
 //each fragment. If it passes the depth test the fragment is written to the pixel buffer.
@@ -24,20 +40,22 @@ class Rasterizer{
         //Line in a triangle.(AB, BC, AC)
         static void drawWireFrame(Vector3f *vertices, IShader &shader, Buffer<Uint32> *pixelBuffer);
 
-        //Proper triangle rasterization with vertex interpolation.
+        //Proper triangle rasterization with vertex interpolation. Zbuffering, post processing
+        //Sadly, not very efficient since it uses floats and scalar operations instead of SIMD
         static void drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint32> *pixelBuffer, Buffer<float> *zBuffer);
 
         //Transforms coordinates from NDC to pixel values
         static void viewportTransform(Buffer<Uint32> *pixelBuffer, Vector3f *vertices);
 
+        //Builds the triangle bounding box
         static void triBoundBox(int &xMax, int &xMin, int &yMax, int &yMin, Vector3f *vertices, Buffer<Uint32> *pixelBuffer);
 
+        //Baricentric coordinates by use of pineda style edge detection
         static float edge(Vector3f &a, Vector3f &b, Vector3f &c);
-
         static bool inside(float edge, float a, float b);
 
+        //Post processing operations
         static float clamp(float n, float lower, float upper);
-
         static int gammaAdjust(float n);
 
     private:
@@ -55,7 +73,6 @@ class Rasterizer{
 
         //Gamma correction look-up table for gamma = 2.2
         static const int gammaTable[256];
-
 };
 
 #endif

+ 18 - 2
include/renderManager.h

@@ -1,6 +1,22 @@
 #ifndef RENDERMANAGER_H
 #define RENDERMANAGER_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-02
+// PURPOSE      : To perform all the high level operations that the actual rendering 
+//                class shouldn't really be concerned with such as: building a render
+//                queue, finding the scene you want to render, and locating the camera.
+//                It also performs the calls to the other manager level classes.
+// ===============================
+// SPECIAL NOTES: I think there is much more that could be offloaded to this class 
+// which is currently being done by the software renderer. For example, the creation of
+// the shader object and the setting of data for each model could easily be prepped earlier
+// And saved into something like a VBO. Alas, I had no idea what I was doing when I wrote this
+// way back and it's time to move on to bigger and better things anyway.
+// ===============================
+
+//Includes
 #include "displayManager.h"
 #include "sceneManager.h"
 #include "softwareRenderer.h"
@@ -21,14 +37,14 @@ class RenderManager{
         void shutDown();
 
         //Performs all high level prep operations that the graphics library
-        //Needs to do before drawin each model in the scene.
+        //Needs to do before beginning to draw each model in the scene.
         void render();
 
     private:
         void buildRenderQueue();
         bool initSoftwareRenderer();
         
-        //This is a pointer to a pointer to allow for scene switching 
+        //This is a pointer to a pointer to allow for scene switching
         SceneManager   * sceneLocator;
         DisplayManager * screen;
 

+ 29 - 28
include/scene.h

@@ -1,63 +1,64 @@
 #ifndef SCENE_H
 #define SCENE_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-10
+// PURPOSE      : Contains all of the world information. The objects that you want to 
+//                render, the camera that represents the viewer and the lights within
+//                a scene. It also performs the view frustrum culling check to see which
+//                objects should be visible by the camera at any given time and keeps
+//                that list updated.
+// ===============================
+// SPECIAL NOTES: I use vectors here instead of arrays. Which I though would be necessary
+// given that I would not know how many items would be loaded. It probably should be 
+// changed in any future update to the engine.
+// ===============================
+
+//Headers
 #include <vector>
 #include <queue>
 #include "model.h"
 #include "camera.h"
 #include "light.h"
 
-//Keeps track of all the lights, models and cameras contained in a current
-//scene. Also performs frustrumc ulling to determine what objects to send to
-//the render queue visibility.
 class Scene{
     public:
-        //Builds a scene based on a path to the folder containing the scene's
-        //content and setup information
+        //Builds scene using path to folder containing content and txt setup file
         Scene(const std::string &sceneFolder);
         ~Scene();
 
-        //Updates all models, lights and cameras in scene
+        //Updates all models, lights and cameras
         void update(unsigned int deltaT);
 
-        //Returns the list of models not culled by the frustrum
+        //Getters used in the setup of the render queue
         std::queue<Model*>* getVisiblemodels();
-
         Camera * getCurrentCamera();
-
         BaseLight * getCurrentLights();
         int getLightCount();
         
+        //Signals issues to scene Manager
+        bool checkIfEmpty();  
 
-        //Used in the scene loading check to determine if models were loaded 
-        //correctly. It sends this info upstream to the scene manager to abort
-        //the load procedure.
-        bool checkIfEmpty();
-        
     private:
+        bool emptyScene;
         Camera mainCamera;
-        
-        BaseLight *lights;
         int lightCount;
+        BaseLight *lights; //Array of lights in scene
 
-        bool emptyScene;
-        std::vector<Model*> modelsInScene;
         //Contains the models that remain after frustrum culling
         std::queue<Model*> visibleModels;
+        std::vector<Model*> modelsInScene;
 
-        //Check if the current scene folder acually exists both in windows and linux
-        //And also checks for accessibility 
+        //Loads scene models, checks by looking for the mesh .If it finds it assumes
+        // (dangerously) that all the other texture data also exists
+        bool loadContent(const std::string &baseFilePath, const std::string &sceneName);
+        //Check if scene folder acually exists and also checks accessibility 
         bool findSceneFolder(const std::string &scenePath);
-
-        //Loads scene models, checks first if they exist by looking for the 
-        //mesh .If it finds it assumes (dangerously) that all the other 
-        //texture data also exists
         void loadSceneModel(const std::string &baseFilePath, const TransformParameters &init);
+        
 
-        bool loadContent(const std::string &baseFilePath, const std::string &sceneName);
-
-        //Cull objects that should not be visible and add the visible ones to the 
-        //visibleModels list for rendering 
+        //Finds objects that the camera can see
         void frustrumCulling();
 };
 

+ 19 - 5
include/sceneManager.h

@@ -1,11 +1,23 @@
 #ifndef SCENEMANAGER_H
 #define SCENEMANAGER_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-10
+// PURPOSE      : Managing the switching of scenes, loading unloading etc, and updating
+//                the current scene. It also returns the currently loaded scene to any
+//                other manager system that wants that information. 
+// ===============================
+// SPECIAL NOTES: The reason I believe you need a scene manager class and not have the 
+// the scenes do all of this themselves is that I don't want to have to update all 
+// pointers to the scene every time that changes. Instead you just point to the scenemanager
+// and that keeps track of the scene itself.
+// ===============================
+
+//Headers
 #include "scene.h"
-//Add an enum in the future with the different scenes that it should be able to
-//render
-class SceneManager{
 
+class SceneManager{
     public:
         //Dummy Constructor / Destructor
         SceneManager();
@@ -22,14 +34,16 @@ class SceneManager{
         void update(unsigned int deltaT);
 
         //Called by the rendermanager to prep the render queue 
+        //Also called by the input manager as a precaution to avoid dangling pointers
         Scene* getCurrentScene();
+
     private:
         bool loadScene(std::string sceneID);
-        bool closeScene();
 
+        //String could probably be an enum instead, but it's easier this way to build
+        //the relative paths if it is a string.
         std::string currentSceneID;
         Scene* currentScene;
 };
 
-
 #endif

+ 112 - 76
include/shader.h

@@ -1,6 +1,19 @@
 #ifndef SHADER_H
 #define SHADER_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-12
+// PURPOSE      : Emulate modern programmable vertex and fragment shaders. Allow texture
+//                reading and full Physically based rendering models. 
+// ===============================
+// SPECIAL NOTES: I kpet the older shaders that I wrote while working towards
+// building the final PBR model because I thought it would be nice to see the progression
+// Although using pure interface classes would seem to incur a perforamnce
+// penalty through pointer chasing I did not measure it through profiling.
+// ===============================
+
+//Headers
 #include "vector3D.h"
 #include "matrix.h"
 #include "texture.h"
@@ -9,7 +22,9 @@
 //Shader Interface for a class that emulates modern GPU fragment and vertex shaders
 struct IShader {
     virtual ~IShader() {};
-    virtual Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,const Vector3f &textureVals,const Vector3f &tangent, const Vector3f &light, int index) = 0;
+    virtual Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,
+                            const Vector3f &textureVals,const Vector3f &tangent,
+                            int index,  const Vector3f &light = Vector3f{1,1,1}) = 0;
     virtual Vector3f fragment(float u, float v) = 0;
 };
 
@@ -19,7 +34,10 @@ struct FlatShader : public IShader {
     float varIntensity;
     Vector3f rgb{255,255,255};
 
-    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,const Vector3f &textureVals,const Vector3f &tangent, const Vector3f &light, int index) override{
+    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,
+                    const Vector3f &textureVals,const Vector3f &tangent,
+                    int index, const Vector3f &light) override
+    {
         varIntensity = std::max(0.0f,normal.dotProduct(light));
         return MVP.matMultVec(vertex); //Transforms verts into projected space
     }
@@ -33,30 +51,43 @@ struct FlatShader : public IShader {
 //More Complex shader that calculates a per-vertex intensity and interpolates 
 //through the fragments of the triangle
 struct GouraudShader : public IShader {
+    //Per object data
     Matrix4 MVP, MV, V, N;
-    float ambientStrength = 0.05, diffStrength = 0, specularStrength = 0.5, spec = 0;
-    Vector3f ambient, diffuse, specular;
     Vector3f lightColor1{1,1,1}, lightColor2{0,0,1}, lightColor3{1,1,1};
-    Vector3f varying_diffuse, varying_specular, reflectDir, viewDir, light2, normal2;
+    float ambientStrength = 0.05, diffStrength = 0, specularStrength = 0.5, spec = 0;
     Vector3f rgb{255,255,255};
 
-    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,const Vector3f &textureVals,const Vector3f &tangent, const Vector3f &light, int index) override{
-        normal2 = N.matMultDir(normal).normalized();
-        light2 = V.matMultDir(light).normalized();
-        reflectDir = Vector3f::reflect(-light2, normal);
+    //Per vertex data
+    Vector3f varying_diffuse, varying_specular, reflectDir, viewDir, lightDir, correctNormal;
+
+    //Per pixel data
+    Vector3f ambient, diffuse, specular;
+
+    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,
+                    const Vector3f &textureVals,const Vector3f &tangent,
+                    int index, const Vector3f &light) override
+    {   
+        //Vertex attributes
+        correctNormal = N.matMultDir(normal).normalized();
+        lightDir = V.matMultDir(light).normalized();
+        reflectDir = Vector3f::reflect(-lightDir, correctNormal);
         viewDir = MV.matMultVec(vertex).normalized();
+        
+        //Values to be interpolated
         varying_specular.data[index] = std::pow( std::max( -viewDir.dotProduct(reflectDir), 0.0f), 32.0f);
-        varying_diffuse.data[index] = std::max(0.0f, (normal).dotProduct(-light2));
+        varying_diffuse.data[index] = std::max(0.0f, (correctNormal).dotProduct(-lightDir));
+
         return MVP.matMultVec(vertex);
     }
 
     Vector3f fragment(float u, float v) override{
-        ambient = lightColor1 * ambientStrength;
-
+        //Interpolating
         diffStrength = varying_diffuse.x + u*(varying_diffuse.y - varying_diffuse.x) + v*(varying_diffuse.z - varying_diffuse.x);
-        diffuse = lightColor2 * diffStrength;
-
         spec = varying_specular.x + u*(varying_specular.y - varying_specular.x) + v*(varying_specular.z - varying_specular.x);
+
+        //Phong reflection model
+        ambient = lightColor1 * ambientStrength;
+        diffuse = lightColor2 * diffStrength;
         specular = lightColor3 * (specularStrength * spec);
 
         return (ambient + diffuse + specular) * rgb;
@@ -67,18 +98,29 @@ struct GouraudShader : public IShader {
 //Even more complex shader that interpolates normals and calculates intensities per fragment instead
 //instead of per vertex.
 struct PhongShader : public IShader {
+    //Per object data
     Matrix4 MVP, MV, V, N;
     float ambientStrength = 0.05, diffStrength = 0, specularStrength = 0.9, spec = 0;
-    Vector3f normals[3], viewDir[3];
-    Vector3f ambient, diffuse, specular, interpNormal, interpViewDir;
     Vector3f lightColor{0,0.1,1},lightColorSpec{1,1,1};
-    Vector3f varying_diffuse, varying_specular, reflectDir, light2;
     Vector3f rgb{255,255,255};
 
-    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,const Vector3f &textureVals,const Vector3f &tangent, const Vector3f &light, int index) override{
+    //Per vertex data
+    Vector3f normals[3], viewDir[3];
+    Vector3f varying_diffuse, varying_specular, reflectDir, lightDir;
+
+    //Per pixel data
+    Vector3f ambient, diffuse, specular, interpNormal, interpViewDir;
+
+
+    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,
+                    const Vector3f &textureVals,const Vector3f &tangent,
+                    int index, const Vector3f &light) override
+    {
+        //Vertex attributes
         normals[index] = N.matMultDir(normal).normalized();
         viewDir[index] = MV.matMultVec(vertex).normalized();
-        light2 = V.matMultDir(light).normalized();
+        lightDir = V.matMultDir(light).normalized();
+
         return MVP.matMultVec(vertex);
     }
 
@@ -90,11 +132,11 @@ struct PhongShader : public IShader {
         ambient = lightColor * ambientStrength;
 
         //Diffuse
-        diffStrength = std::max(0.0f, (interpNormal.normalized()).dotProduct(light2));
+        diffStrength = std::max(0.0f, (interpNormal.normalized()).dotProduct(lightDir));
         diffuse = lightColor * diffStrength;
         
         //Specular
-        reflectDir = Vector3f::reflect(-light2, interpNormal);
+        reflectDir = Vector3f::reflect(-lightDir, interpNormal);
         spec = std::pow( std::max( (-interpViewDir.normalized()).dotProduct(reflectDir), 0.0f), 50.0f);
         specular = lightColorSpec * (specularStrength * spec);
 
@@ -106,17 +148,24 @@ struct PhongShader : public IShader {
 //Optimized version of Phong shader that uses a half angle instead of individual reflection
 //angles
 struct BlinnPhongShader : public IShader {
+    //Per object data
     Texture *albedoT;
     Matrix4 MVP, MV, V, N;
     float ambientStrength = 0.05, diffStrength=1 , specularStrength= 0.5;
-    float diff, spec, shininess = 128;
+    Vector3f lightColor{1,1,1};
+
+    //Per vertex data
     Vector3f normals[3], viewDir[3], UV[3];
+    float diff, spec, shininess = 128;
+    
+    //Per fragment data
     Vector3f ambient, diffuse, specular, interpNormal, interpViewDir, interpUV;
-    Vector3f lightColor{1,1,1};
     Vector3f halfwayDir, lightDir;
     Vector3f interpCol, white{255,255,255};
 
-    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,const Vector3f &textureVals,const Vector3f &tangent, const Vector3f &light, int index) override{
+    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,
+                    const Vector3f &textureVals,const Vector3f &tangent,
+                    int index, const Vector3f &light) override{
         normals[index] = N.matMultDir(normal).normalized();
         UV[index] = textureVals;
         viewDir[index] = MV.matMultVec(vertex).normalized();
@@ -175,7 +224,9 @@ struct TextureMapShader : public IShader {
     Vector3f ambient, diffuse, specular ;
     Vector3f halfwayDir;
 
-    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,const Vector3f &textureVals, const Vector3f &tangent, const Vector3f &light, int index) override{
+    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,
+                    const Vector3f &textureVals, const Vector3f &tangent,
+                    int index, const Vector3f &light) override{
         //Creating TBN matrix
         normal_WS     = N.matMultDir(normal).normalized();
         tangent_WS    = N.matMultDir(tangent).normalized();
@@ -193,7 +244,7 @@ struct TextureMapShader : public IShader {
     }
 
     Vector3f fragment(float u, float v) override{
-        //Interpolated stuff
+        //Interpolated attributes
         interpCoords   = texCoords[0] + (texCoords[1] - texCoords[0])* u + (texCoords[2] - texCoords[0]) * v;
         interpLightDir = lightDir[0] + (lightDir[1] - lightDir[0])* u + (lightDir[2] - lightDir[0]) * v;
         interpViewDir  = viewDir[0] + (viewDir[1] - viewDir[0])* u + (viewDir[2] - viewDir[0]) * v;
@@ -231,11 +282,9 @@ struct PBRShader : public IShader {
 
     //Light Variables
     Vector3f F0{0.04, 0.04, 0.04}, F0corrected; //Default value dielectric
+    Vector3f *lightDirVal, *lightCol, *lightPos;
     float nDotL, nDotV, ambientInt = 0.01;
     int numLights;
-    Vector3f *lightDirVal;
-    Vector3f *lightCol;
-    Vector3f *lightPos;
 
     //Variables set per vertex
     Vector3f viewDir[3], texCoords[3];
@@ -243,19 +292,15 @@ struct PBRShader : public IShader {
     Matrix4 TBN;
     
     //Interpolated variables
-    Vector3f interpCoords, interpNormal, interpViewDir,
-             interpCol;
+    Vector3f interpCoords, interpNormal, interpViewDir, interpCol;
 
     //Per fragment
-   // Vector3f F, NDF, G ; //Fresnel, normal distribution function and geometry occlusion 
-    Vector3f halfwayDir, radianceOut, ambient;
-    Vector3f specular, kD, kS;
+    Vector3f radianceOut, ambient;
     float interpRough, interpAO, interpMetal;
     float uTexture, vTexture, intPart;
 
     //BRDF functions
     Vector3f fresnelSchlick(float cosTheta, Vector3f &fresnel0 ){
-        //return fresnel0 + (Vector3f(1.0)- fresnel0)* std::pow(2.0,(-5.55473*cosTheta * cosTheta) - 6.98316*cosTheta);
         float invcCosTheta = 1.0 - cosTheta;
         return fresnel0 + (Vector3f(1.0)- fresnel0) * (invcCosTheta * invcCosTheta * invcCosTheta * invcCosTheta * invcCosTheta);
     }
@@ -282,7 +327,10 @@ struct PBRShader : public IShader {
     }
 
     //Vertex shader
-    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,const Vector3f &textureVals, const Vector3f &tangent, const Vector3f &n, int index) override{
+    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,
+                     const Vector3f &textureVals, const Vector3f &tangent,
+                    int index, const Vector3f &light = Vector3f{1,1,1}) override
+    {             
         //Creating TBN matrix
         normal_WS     = N.matMultDir(normal).normalized();
         tangent_WS    = N.matMultDir(tangent).normalized();
@@ -304,7 +352,7 @@ struct PBRShader : public IShader {
 
     //Fragment shader
     Vector3f fragment(float u, float v) override{
-        //Interpolated stuff
+        //Interpolated attributes
         interpCoords   = texCoords[0] + (texCoords[1] - texCoords[0])* u + (texCoords[2] - texCoords[0]) * v;
         interpViewDir  = viewDir[0] + (viewDir[1] - viewDir[0])* u + (viewDir[2] - viewDir[0]) * v;
 
@@ -327,44 +375,59 @@ struct PBRShader : public IShader {
         nDotV = std::max(interpNormal.dotProduct(interpViewDir), 0.0f);
 
         //Setting up Direct Lighting variables
-        radianceOut.zero();
         const int maxLights = numLights;
-        int val;
+
+        //Fresnel, normal distribution function and geometry occlusion 
+        Vector3f F[maxLights];
+        float  NDF[maxLights];
+        float  G[maxLights];
+        
+        //Storing in array for vectorizing
         Vector3f radianceLights[maxLights];
         Vector3f interpLightDir[maxLights];
         Vector3f halfwayDir[maxLights];
-        Vector3f F[maxLights];
+        float  nDotL[maxLights];
         Vector3f numerator[maxLights];
+        float  invDenominator[maxLights];
         Vector3f specular[maxLights];
         Vector3f kD[maxLights];
-        float  NDF[maxLights];
-        float  nDotL[maxLights];
-        float  invDenominator[maxLights];
-        float  G[maxLights];
+        
+        //Interpolating each light direction for every light
+        int val;
         for(int i = 0; i < maxLights; ++i ){
             val = i*3;
             interpLightDir[i] = (lightDirVal[val] +  (lightDirVal[val + 1] - lightDirVal[val])* u +  (lightDirVal[val + 2] - lightDirVal[val]) * v).normalized();
         }
 
+        //Per light illumination calculations that can be simdified
+        //Currently uses widest SIMD array to perform all light iterations in one trip
+        //Which I believe leaves some extra 
         #pragma omp simd
         for(int light = 0; light < maxLights; ++light ){
             halfwayDir[light] = (interpLightDir[light] + interpViewDir);
             halfwayDir[light] = halfwayDir[light].normalized();
             nDotL[light] = std::fmax(interpNormal.dotProduct(interpLightDir[light]), 0.0f);
-            //#pragma distribute_point
+
+            //No problem vectorizing these functions because they are inlined by the compiler
+            //And also only consist of math operations to the vectors
             F[light]     = fresnelSchlick(std::fmax(halfwayDir[light].dotProduct(interpViewDir), 0.0f), F0corrected);
             NDF[light]   = distributionGGX(interpNormal, halfwayDir[light], interpRough); 
             G[light]     = GeometrySmith(interpRough, nDotL[light] , nDotV);
-           // #pragma distribute_point
+
             numerator[light] = F[light] * G[light]*NDF[light];
             invDenominator[light]  = 1.0f / std::fmax(4.0f * (nDotL[light] * nDotV), 0.001f);
             specular[light]  = numerator[light] * invDenominator[light];
-            //#pragma distribute_point
+
+            //kd is 1 - kf which is the stuff to the right of the vecotr 
             kD[light] = (Vector3f(1.0f) - F[light])*invMetal;
-            radianceLights[light] = (kD[light] * (interpCol * (M_1_PIf32)) + specular[light] ) * nDotL[light] * lightCol[light];
 
+            //The rendering equation result for a given light
+            radianceLights[light] = (kD[light] * (interpCol * (M_1_PIf32)) + specular[light] ) * nDotL[light] * lightCol[light];
         }
 
+        //Summing up all radiance values since SIMD won't work if I do this within the
+        //previous loop
+        radianceOut.zero();
         for(int i = 0; i < maxLights; ++i) {
             radianceOut += radianceLights[i];
         }
@@ -374,33 +437,6 @@ struct PBRShader : public IShader {
 
         return ambient + radianceOut;
     }
-
+    
 };
-
-        //#pragma omp simd simdlen(512)
-        // for(int light = 0; light < maxLights; ++light ){
-        //     halfwayDir = (interpLightDir[light] + interpViewDir).normalized();
-        //     nDotL = std::max(interpNormal.dotProduct(interpLightDir[light]), 0.0f);
-
-        //     //We assume the only lights in the scene are far away so there is no attenuation
-            
-        //     //Setting up BRDF
-        //     F   = fresnelSchlick(std::max(halfwayDir.dotProduct(interpViewDir), 0.0f), F0corrected);
-        //     NDF = distributionGGX(interpNormal, halfwayDir, interpRough); 
-        //     G   = GeometrySmith(interpRough);
-
-        //     //Calculating specular component of BRDF
-        //     Vector3f numerator = F * (G*NDF);
-        //     invDenominator  = 1.0f / std::max(4.0f * nDotL * nDotV, 0.001f);
-        //     specular  = numerator * invDenominator;
-
-        //     //Calculating the full rendering equation for a single light
-        //     //kS = F;
-        //     kD = (Vector3f(1.0f) - F)*invMetal;
-        //     //kD = kD *invMetal; 
-        //     radianceLights[light] = ( (kD * (interpCol * (1/M_PI)) + specular ) * nDotL * lightCol[light]);
-        // }
-
-
-
 #endif

+ 38 - 21
include/softwareRenderer.h

@@ -1,6 +1,24 @@
 #ifndef SRENDERER_H
 #define SRENDERER_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-10
+// PURPOSE      : Core graphics class that performs rendering for different mesh types. 
+//                The core rendering function is drawTriangularMesh that contains the logic
+//                for drawing triangular mesh objects as described in the mesh class.
+//                It attempts to recreate a similar pipeline to the old OpenGL 2  one
+//                due to its simplicity.
+// ===============================
+// SPECIAL NOTES: As mentioned in the manager level class, many tasks done here should be
+// offloaded to the manager class to reduce coupling. Specifically, the buffers should be
+// moved to the manager class and treated simply as rendertargets for the renderer to draw
+// to. There is also no real need for the render class to have knowledge of my definition
+// of a model and camera. On a second pass I would rebuild this from the ground up with a 
+// similar structure to opengl's VBO, VAO and EBO's system. 
+// ===============================
+
+//Headers
 #include "rasterizer.h" 
 #include "buffer.h"
 #include "model.h"
@@ -8,49 +26,47 @@
 #include "light.h"
 
 class SoftwareRenderer {
-
     public:
         //Dummy Constructor / Destructor
         SoftwareRenderer();
         ~SoftwareRenderer();
 
-        //Creates all buffers and preps everything for for rendering
+        //Creates all buffers and preps everything for model rendering
         bool startUp(int w, int h);  
         void shutDown();      
 
         //Overview:
-        //01.-Gets pointers to render data form mesh
-        //02.-Builds MVP 
-        //03.-Iterates through all triangle faces
-        //04.-Runs backface culling algo
-        //05.-Applies vertex shader per vertex
-        //06.-Performs clipping of triangles outside frustrum
-        //07.-Applies perspective divide
-        //08.-Sends to triangle rasterizer
-        //09.-NDC -> viewport transform
-        //10.-Iterates through triangle bounding box 
-        //11.-Calculates barycentric coordinates
+        //01.-Gets pointers to mesh data from model
+        //02.-Builds Model view and projection matrix
+        //03.-Iterates through all triangle faces (in parallel!)
+        //04.-Runs backface culling algo uisng facet normmals
+        //05.-Applies vertex shader per vertex in face
+        //06.-Performs clipping of triangles fully outside view frustrum 
+        //07.-Applies perspective divide using "hidden" w coordinate
+        //08.-Sends shader data and triangle to rasterizer
+        //09.-NDC to viewport transform
+        //10.-Builds triangle bounding box and Iterates through
+        //11.-Calculates perspective correct barycentric coordinates
         //12.-Culls pixels outside of triangle or screen
-        //13.-Runs fragment shader
-        //14.-zBuffer update
-        //15.-Writes to frame buffer
-        //16.-Swap buffer
+        //13.-Runs fragment shader per pixel that passes depth buffer check
+        //14.-updates zBuffer with new value and gamma corrects color
+        //15.-Writes to pixel frame buffer 
         void drawTriangularMesh(Model * currentModel);
 
-        void clearBuffers();
-
         //Returns pixel buffer
         Buffer<Uint32>* getRenderTarget();
+        void clearBuffers();
 
+        //Set up methods called by rendermanager
         void setCameraToRenderFrom(Camera * camera);
-
         void setSceneLights(BaseLight * lights, int numLights);
+
     private:
         //Buffer methods
         bool createBuffers(int w, int h);
 
         //Primitive level methods
-        void buildTri(Vector3i &f, Vector3f *trianglePrim, std::vector<Vector3f> &vals);
+        void packDataIntoTris(Vector3i &f, Vector3f *trianglePrim, std::vector<Vector3f> &vals);
         void perspectiveDivide(Vector3f *clippedVertices);
 
         //Culling and clipping methods
@@ -65,6 +81,7 @@ class SoftwareRenderer {
         int mNumLights;
         BaseLight *mLights;
 
+        //Buffers
         Buffer<float> * zBuffer;
         Buffer<Uint32> * pixelBuffer;
 };

+ 20 - 3
include/texture.h

@@ -1,23 +1,40 @@
 #ifndef TEXTURE_H
 #define TEXTURE_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-02
+// PURPOSE      : To store texture data for retrieval during the pixel shader phase.
+//                it also has to be capable of storing all the major kinds of textures
+//                that are used in a physically based renderer.
+// ===============================
+// SPECIAL NOTES: The two separate methods to get pixel values are not good style,
+// and should probably be changed. The reason they're there is because of the different
+// return statement for each. Should probably become either different classes or just
+// a more general solution.
+// ===============================
+
+//Headers
 #include <string>
 #include "vector3D.h"
 
 class Texture{
     public:
         Texture(std::string path, std::string type); 
-
         ~Texture();
 
         Vector3f getPixelVal(float u, float v);
         float getIntensityVal(float u, float v);
 
     private:
-        int bilinearFiltering(float u, float v);
-        void tileData();
         float *pixelData;
         int width, height, channels, tileW = 32, tileH = 32, widthInTiles;
+
+        //Currently disabled after tiling has been implemented
+        int bilinearFiltering(float u, float v);
+
+        //Reorganizes pixel data into a more cache friendly form
+        void tileData();
 };
 
 #endif

+ 18 - 1
include/vector3D.h

@@ -1,6 +1,20 @@
 #ifndef VECTOR3D_H
 #define VECTOR3D_H
 
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-18
+// PURPOSE      : Template vector class used for all vector operations, 3d, 2d and 4d
+//                vectors included. It is capable of performing most normal vector 
+//                operations and allows for access using both x,y,z and array indexing
+// ===============================
+// SPECIAL NOTES: Homogeneous coordinates are used with 3D vectors by hiding in the 
+//                implementation a 4th variable w taht contains the 4th coordinate.
+//                In the words of Douglas Adams:
+//   "This has made a lot of people very angry and been widely regarded as a bad move"
+// ===============================
+
+//Headers
 #include <string>
 #include <type_traits>
 #include "math.h"
@@ -75,6 +89,8 @@ struct Vector3{
     T length() const
     {return std::sqrt(x*x + y*y + z*z);}
 
+    //Used to account for edge case of len = 0 but branching impedes SIMD 
+    //auto vectorization
     Vector3 &normalized(){
         T len = length();
         T factor = 1.0f / len;
@@ -85,6 +101,7 @@ struct Vector3{
         return *this;
     }
 
+    //Only used for blinn shading within specular reflection calculations
     static Vector3 reflect(const Vector3 &I, const Vector3 &N){
         return I - ((N * I.dotProduct(N)) * 2.0f);
     }
@@ -109,7 +126,7 @@ struct Vector3{
     }
 };
 
-//Shorthands for the common vector types we use
+//Shorthands for the common vector types
 typedef Vector3<float> Vector3f; 
 typedef Vector3<int> Vector3i; 
 

+ 10 - 0
src/camera.cpp

@@ -1,3 +1,9 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-10
+// ===============================
+
+//Headers
 #include "camera.h"
 
 Camera::Camera(){
@@ -8,6 +14,8 @@ Camera::Camera(){
     cameraFrustrum.updatePlanes(viewMatrix, position);
 }
 
+//Updates target and position based on camera movement mode.
+///Also updates view matrix and projection matrix for rendering
 void Camera::update(unsigned int deltaT){
     if(orbiting){
         float ang    = 2 * M_PI * static_cast<float>(SDL_GetTicks()) / 3e4;
@@ -25,10 +33,12 @@ void Camera::update(unsigned int deltaT){
     projectionMatrix = Matrix4::projectionMatrix(cameraFrustrum.fov, cameraFrustrum.AR, cameraFrustrum.near, cameraFrustrum.far);
 }
 
+//View frustrum culling using a models AAB
 bool Camera::checkVisibility(AABox *bounds){
     return cameraFrustrum.checkIfInside(bounds);
 }
 
+//Used by input to reset camera to origin in case user loses their bearings
 void Camera::resetCamera(){
     position = Vector3f(0, 0, 8.0);
     target.zero();  

+ 32 - 23
src/displayManager.cpp

@@ -1,9 +1,17 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-10
+// ===============================
+
+//Includes
 #include "displayManager.h"
 
-//Dummy constructurs/destructors
+//Dummy constructors/destructors
 DisplayManager::DisplayManager(){}
 DisplayManager::~DisplayManager(){}
 
+//Initializes the window and obtains the surface on which we draw.
+//Also first place where SDL is initialized. 
 bool DisplayManager::startUp(){
     bool success = true;
     if( !startSDL() ){
@@ -22,14 +30,30 @@ bool DisplayManager::startUp(){
     return success;
 }
 
+//Closes down sdl and destroys window.
+//SDL surface is also destroyed in the call to destroy window
 void DisplayManager::shutDown(){
-
     SDL_DestroyWindow(mWindow);
     mWindow = nullptr;
-
     SDL_Quit();
 }
 
+//Applies the rendering results to the window screen by copying the pixelbuffer values
+//to the screen surface.
+void DisplayManager::swapBuffers(Buffer<Uint32> *pixels){
+    //Allows surface editing 
+    SDL_LockSurface(mSurface);
+
+    //Copy pixels buffer resuls to screen surface
+    memcpy(mSurface->pixels, pixels->buffer, pixels->mHeight*pixels->mPitch);
+    SDL_UnlockSurface(mSurface);
+
+    //Apply surface changes to window
+    SDL_UpdateWindowSurface(mWindow);
+
+}
+
+//Entry point to SDL
 bool DisplayManager::startSDL(){
     if( SDL_Init(SDL_INIT_VIDEO) != 0){
         printf("Failed to initialize SDL. Error: %s\n", SDL_GetError() );
@@ -38,6 +62,7 @@ bool DisplayManager::startSDL(){
     return true;
 }
 
+//Inits window with the display values crated at compile time
 bool DisplayManager::createWindow(){
     mWindow = SDL_CreateWindow( "SoftwareRenderer", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
     if( mWindow == nullptr){
@@ -47,6 +72,10 @@ bool DisplayManager::createWindow(){
     return true;
 }
 
+//Gets the screen surface
+//I know this is "Old" SDL and it's not really recommended anymore
+//But given that I am doing 100% cpu based rendering it makes sense
+//After all I'm not usin any of the new functionality
 bool DisplayManager::createScreenSurface(){
     mSurface = SDL_GetWindowSurface(mWindow);
     if(mSurface == NULL){
@@ -54,24 +83,4 @@ bool DisplayManager::createScreenSurface(){
         return false;
     }
     return true;
-}
-
-void DisplayManager::clear(){
-    //Clear to black
-    SDL_LockSurface(mSurface);
-    SDL_memset(mSurface->pixels,0 ,mSurface->h * mSurface->pitch);
-    SDL_UnlockSurface(mSurface);
-}
-
-void DisplayManager::swapBuffers(Buffer<Uint32> *pixels){
-    //Allows surface editing 
-    SDL_LockSurface(mSurface);
-
-    //Copy pixels buffer resuls to screen surface
-    memcpy(mSurface->pixels, pixels->buffer, pixels->mHeight*pixels->mPitch);
-    SDL_UnlockSurface(mSurface);
-
-    //Update surface to window
-    SDL_UpdateWindowSurface(mWindow);
-
 }

+ 29 - 17
src/engine.cpp

@@ -1,32 +1,45 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-02
+// ===============================
+
+//Headers
 #include "engine.h"
 
 //Dummy constructors and destructors
 Engine::Engine(){}
 Engine::~Engine(){}
 
-//Starts up subsystems in an order that satifies their dependencies
+//Starts up subsystems in an order that satifies their dependencies.
+//If at any point any of the subsystem fails to initialize, the success flag is raised
+//and the loading is exited early. This serves to avoid any further fails in the 
+//initialization routine that might cause seg faults.
 bool Engine::startUp(){
     bool success = true;
-    //Start up of all SDL related content
+    //Start up of all SDL Display related content
     if( !gDisplayManager.startUp() ){
         success = false;
         printf("Failed to initialize window manager.\n");
     }
     else{
-        //Loads default scene
+        //Initis scene manager and loads default scene
         if( !gSceneManager.startUp() ){
             success = false;
             printf("Failed to initialize scene manager.\n");
         }
         else{
-            //Initializes renderer and connects it to the window manager
-            //Also gets pointer to current scene
+            //Initializes rendererer manager, which is in charge of high level
+            //rendering tasks (render queue, locating render scene etc)
+            //It gets passed references to the other major subsystems for use later
+            //on setup of the render queue.
             if( !gRenderManager.startUp(gDisplayManager, gSceneManager) ){
-            success = false;
-            printf("Failed to initialize render manager.\n");
-            
+                success = false;
+                printf("Failed to initialize render manager.\n");
             }
             else{
+                //Initializing input manager that manages all mouse, keyboard and
+                //mousewheel input. It needs access to the scene manager to apply the
+                //changes on the scene caused by user input. 
                 if ( !gInputManager.startUp(gSceneManager) ){
                     success = false;
                     printf("Failed to initialize input manager.\n");
@@ -52,9 +65,8 @@ void Engine::shutDown(){
     printf("Closed display manager.\n");
 }
 
-//Runs main application loop
+//Runs main application loop 
 void Engine::run(){
-
     //Main flags
     bool done = false;
 
@@ -67,26 +79,26 @@ void Engine::run(){
     printf("Entered Main Loop!\n");
     while(!done){
         ++count;
-        start = SDL_GetTicks();
+        start = SDL_GetTicks(); //Could probably be its own timer class, but we're keeping things simple here
 
         //Handle all user input
-        //Switches scene too
+        //Any changes to the scene are directly sent to the respective objects in
+        //the scene class. Also sets exit flag based on user input.
         gInputManager.processInput(done, deltaT);
         
         //Update all models, camera and lighting in the current scene
+        //Also performs view frustrum culling to determine which objects aare visible
         gSceneManager.update(deltaT);
 
-        //Update Rendering Queue and draw each item 
+        //Contains the render setup and actual software rendering loop
         gRenderManager.render();
 
-        //Stats about frame
+        //Monitoring time taken per frame to gauge engine performance
         deltaT = SDL_GetTicks() - start;
-        printf("%2.1d: Loop elapsed time (ms):%d\n",count, deltaT);
+        printf("%2.1d: Frame elapsed time (ms):%d\n",count, deltaT);
         total += deltaT;
         if(count == 500) break;
     }
-
     printf("Closing down engine.\n");
     printf("Average frame time over %2.1d frames:%2.fms.\n", count, total/(float)count);
-    
 }

+ 13 - 6
src/geometry.cpp

@@ -1,3 +1,9 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-19
+// ===============================
+
+//Headers
 #include "geometry.h"
 #include <limits>
 #include <math.h>
@@ -26,11 +32,15 @@ void AABox::buildAABB(const Mesh &mesh){
     maxPoints = maxVals;
 }
 
+//Any change in the posiiton, rotation, scale of an object will cause a change
+//in the AABB This function rebuilds it based on those changes
+//which are contained within a model matrix.
 void AABox::update(const Matrix4 &modelMatrix){
     Vector3f minVals(std::numeric_limits<float>::max());
     Vector3f maxVals(std::numeric_limits<float>::min());
     Vector3f vertices[8];
 
+    //Reconstructing the 8 vertices of an AABB from the min and max valuesin the struct
     vertices[0] = Vector3f(minPoints.x, minPoints.y, minPoints.z);
     vertices[1] = Vector3f(maxPoints.x, minPoints.y, minPoints.z);
     vertices[2] = Vector3f(minPoints.x, maxPoints.y, minPoints.z);
@@ -61,7 +71,8 @@ void AABox::update(const Matrix4 &modelMatrix){
 
 
 //---------------------------------PLANE------------------------------------//
-
+//Returns a negative value if not aligned in the same direction of plane normal
+//which I established to be pointing towards the interior of the camera frustrum
 float Plane::distance(const Vector3f &points){
     return normal.dotProduct(points) + D;
 }
@@ -153,8 +164,4 @@ bool Frustrum::checkIfInside(AABox *box){
         if (out == 8) return false;
     }
     return true;
-}
-
-
-
-
+}

+ 30 - 5
src/inputManager.cpp

@@ -1,5 +1,12 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-02
+// ===============================
+
+//Headers
 #include "inputManager.h"
 
+//Dummy constructors and destructors
 InputManager::InputManager(){}
 InputManager::~InputManager(){}
 
@@ -7,7 +14,7 @@ bool InputManager::startUp(SceneManager &sceneManager){
     sceneController = &sceneManager;
     sceneCamera = (sceneController->getCurrentScene()->getCurrentCamera());
     
-    //Only really care about relative mouse motion because we're building a space camera
+    //Only really care about relative mouse motion because we're building a free camera
     bool success = !SDL_SetRelativeMouseMode(SDL_TRUE);
     return success;
 }
@@ -16,6 +23,8 @@ void InputManager::shutDown(){
     //Nothing to do yet
 }
 
+//Goes through the list of every event that has occurred since the last call
+//of this function and either performs and exit or sends the result to the even handler
 void InputManager::processInput(bool &done, unsigned int deltaT){
     SDL_Event event;
     while(SDL_PollEvent(&event)){
@@ -33,14 +42,25 @@ void InputManager::processInput(bool &done, unsigned int deltaT){
     }
 }
 
-//Handles user keyboard input
-//TODO: handle mouse input 
+//Handles all the current valid user events:
+//1. User requested quits
+//2. Keyboard presses
+//3. Mouse movement
+//4. Mouse clicks
+//5. Mouse wheel movement
 void InputManager::handleEvent(SDL_Event * event, bool &done, unsigned int deltaT){
+    //Normally would be multiplied by deltaT but caused issues with large fps 
+    //differences
     float speed = sceneCamera->camSpeed;// * deltaT;
+
     //Handling keyboard input
     if( event->type == SDL_KEYDOWN ){
-        //keys 1-5 switch to different scene
-        //WASD control strafe movement
+
+        //Keys 1-6 handle scenes switching
+        //Key ESC handles exit
+        //Keys wasdqe handle strafing and moving up and down
+        //Key r handles resetting camera
+        //Key tab handles toggleing orbit mode
         std::string sceneID = "0";
         switch( event->key.keysym.sym )
         {   
@@ -164,7 +184,10 @@ void InputManager::handleEvent(SDL_Event * event, bool &done, unsigned int delta
             sceneCamera->side    = sceneCamera->front.crossProduct(sceneCamera->up);
         }
     }
+    //Handling mouse wheel movement
+    //Changes zoom levels in increments of 5 degrees (2.5 really cause FOV is half angle)
     else if( event->type == SDL_MOUSEWHEEL){
+
         float zoom = 5.0f;
         float fov  = sceneCamera->cameraFrustrum.fov; 
         if(event->wheel.y > 0){ // scroll up
@@ -174,6 +197,7 @@ void InputManager::handleEvent(SDL_Event * event, bool &done, unsigned int delta
             fov += zoom;
         }
 
+        //Limiting the FOV range to avoid low FPS values or weird distortion
         if(fov < 20){
             fov = 20;
         }
@@ -181,6 +205,7 @@ void InputManager::handleEvent(SDL_Event * event, bool &done, unsigned int delta
             fov = 120;
         }
 
+        //Updating the camera frustrum
         sceneCamera->cameraFrustrum.fov = fov;
     }
 }

+ 7 - 1
src/main.cpp

@@ -1,8 +1,14 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-02
+// PURPOSE      : Program initialization and shutdown
+// ===============================
+
 #include "engine.h"
 
 int main(int argc, char *argv[]){
 
-    Engine SSGE; //Simple Software Graphics Engine
+    Engine SSGE; //"Simple" Software Graphics Engine
     if(SSGE.startUp()){
         SSGE.run();
     }

+ 25 - 9
src/matrix.cpp

@@ -1,6 +1,16 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-04
+// ===============================
+
+//Headers
 #include "matrix.h"
 #include <math.h>
 
+//The full matrix vector multiplication routine 
+//using the full 4x4 values.
+//Also changes the secret w component in the vec3 to w 
+//which is only really ever used in perspective divide and clipping
 Vector3f Matrix4::matMultVec(const Vector3f &vec){
     Vector3f newVec(0,0,0);
     float w2 = 0;
@@ -29,6 +39,8 @@ Vector3f Matrix4::matMultVec(const Vector3f &vec){
     return newVec;
 }
 
+//Used to multiply direction vectors or when you do not what your vector to be
+//translated. Implicitely makes the matrix a 3x3
 Vector3f Matrix4::matMultDir(const Vector3f &vec){
     Vector3f newVec(0,0,0);
     newVec.x = vec.x*(*this)(0,0)+
@@ -195,9 +207,6 @@ Matrix4 Matrix4::inverse(){
 
     det = mMatrix[0] * inverseMat(0,0) + mMatrix[1] * inverseMat(1,0) + mMatrix[2] * inverseMat(2,0) + mMatrix[3] * inverseMat(3,0);
 
-   // if (det == 0)
-        //return false;
-
     det = 1.0 / det;
 
     for (i = 0; i < 4; ++i){
@@ -206,8 +215,6 @@ Matrix4 Matrix4::inverse(){
         }   
     }
 
-
-    //return true;
     return inverseMat;
 }
 
@@ -239,6 +246,7 @@ Matrix4 Matrix4::operator*(Matrix4 &rhs){
     return results;
 }
 
+// 1-15 values 
 Matrix4 Matrix4::makeTestMat(){
     Matrix4 testMat;
     int n = 4;
@@ -260,6 +268,7 @@ Matrix4 Matrix4::unitMatrix(){
     testMat(3,3) = 1;
     return testMat;
 }
+
 //Uses ZYX convention for rotation
 Matrix4 Matrix4::fullRotMat(float alpha, float beta, float gamma){
     Matrix4 rotMat;
@@ -293,6 +302,7 @@ Matrix4 Matrix4::fullRotMat(float alpha, float beta, float gamma){
     return rotMat;
 }
 
+//Fills values along diagonal only
 Matrix4 Matrix4::scaleMat(float scaleX, float scaleY, float scaleZ){
     Matrix4 scaleMat;
     scaleMat(0,0) = scaleX;
@@ -302,6 +312,7 @@ Matrix4 Matrix4::scaleMat(float scaleX, float scaleY, float scaleZ){
     return scaleMat;
 }
 
+//Could porbably be combined with scale mat
 Matrix4 Matrix4::translateMat(float dx, float dy, float dz){
     Matrix4 transMat;
     transMat(0,0) = 1;
@@ -313,7 +324,8 @@ Matrix4 Matrix4::translateMat(float dx, float dy, float dz){
     transMat(3,3) = 1;
     return transMat;
 }
-
+//Multiplication order is very important
+// translation *(rotation*(scaling)) to avoid unexpected behaviour
 Matrix4 Matrix4::transformMatrix(TransformParameters transform){
     Matrix4 rotMatrix = Matrix4::fullRotMat(transform.rotation.x,
                          transform.rotation.y, transform.rotation.z);
@@ -326,6 +338,8 @@ Matrix4 Matrix4::transformMatrix(TransformParameters transform){
     return  translationMatrix*(temp);
 }
 
+//Moves the whole world to place the origin at the current camera position
+//And wrt its direction
 Matrix4 Matrix4::lookAt(Vector3f& position, Vector3f& target, Vector3f& temp){
     //Gram–Schmidt process
     Vector3f forward = (position - target).normalized();
@@ -336,7 +350,6 @@ Matrix4 Matrix4::lookAt(Vector3f& position, Vector3f& target, Vector3f& temp){
     //The idea is that we don't care where the camera is, we only care about what
     //transformation would put the origin at the camera world space position
     //With the z axis behind the camera.
-    //I bet you this will be really confusing in a couple of weeks
     Matrix4 worldToCam;
     
     //First row
@@ -362,7 +375,8 @@ Matrix4 Matrix4::lookAt(Vector3f& position, Vector3f& target, Vector3f& temp){
 
     return worldToCam;
 }
-
+//Assumes a symmetrical frustrum with euqal fov for horizontal and vertical
+//Also uses the inverse z trick to in theory improve zbuffer precision
 Matrix4 Matrix4::projectionMatrix(float fov, float AR, float near, float far){
     Matrix4 projectionMat;
     float tanHalfFOVInverse   =  1/tan( (fov/2) * (M_PI / 180) );
@@ -373,7 +387,7 @@ Matrix4 Matrix4::projectionMatrix(float fov, float AR, float near, float far){
     //Second row
     projectionMat(1,1) = AR * tanHalfFOVInverse; //near / top (top = right /AR)
 
-    //Third row (Calculated for 1- 0)
+    //Third row (Calculated for 1- 0) Inverse z buffer black magic
     projectionMat(2,2) =  (near) / (far - near);
     projectionMat(2,3) =  (far * near) / (far - near);
     
@@ -383,6 +397,8 @@ Matrix4 Matrix4::projectionMatrix(float fov, float AR, float near, float far){
     return projectionMat;
 }
 
+//Transposed to get world-tangent transform
+//You can transpose it instead of inverting it because it's orthogonal
 Matrix4 Matrix4::TBNMatrix(const Vector3f &tangent, const Vector3f &biTangent, const Vector3f &normal){
     Matrix4 tangentMat;
 

+ 13 - 5
src/mesh.cpp

@@ -1,3 +1,9 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-03
+// ===============================
+
+//Headers
 #include "mesh.h"
 
 void Mesh::describeMesh(){
@@ -15,7 +21,10 @@ void Mesh::buildFacetNormals(){
         fNormals.push_back((N1.crossProduct(N2)).normalized());
     }
 }
-
+//Builds per vertex tangent and bitangents by first finding tangeents and bitangents
+//per face. Then taking the average value at each vertex and then renormalizing because
+//average process might be altering direction. Then also corrects for any incorrect handedness
+//issues. Finally sets the correct vectors in a per vertex fashion
 void Mesh::buildTangentSpace(){
     std::vector<std::vector<Vector3f>> tempTangents(numVertices);
     std::vector<std::vector<Vector3f>> tempBiTangents(numVertices);
@@ -23,6 +32,7 @@ void Mesh::buildTangentSpace(){
 
     //Extract the tangent and bitangentn of each surface triangle
     //Assign the value to a temporary vector of vectors of vector3's (yikes)
+    //“When I wrote this, only God and I understood what I was doing. Now, God only knows.”
     for(int i = 0; i < numFaces; ++i){
         Vector3i vIndices = vertexIndices[i];
         Vector3i tIndices = textureIndices[i];
@@ -108,23 +118,21 @@ void Mesh::buildTangentSpace(){
         Vector3f biTangentV1 = biTangents[vIndices.data[1]];
         Vector3f biTangentV2 = biTangents[vIndices.data[2]];
 
+        //Renormalizing
         tangentV0  = (tangentV0 - (normalV0*tangentV0.dotProduct(normalV0))).normalized();
         tangentV1  = (tangentV1 - (normalV1*tangentV1.dotProduct(normalV1))).normalized();
         tangentV2  = (tangentV2 - (normalV2*tangentV2.dotProduct(normalV2))).normalized();
 
-
+        //Correcting handedness
         if (biTangentV0.dotProduct(normalV0.crossProduct(tangentV0)) < 0.0f){
-            //printf("here0!\n");
             tangentV0 = tangentV0  * -1.0f;
         }
 
         if (biTangentV1.dotProduct(normalV1.crossProduct(tangentV1)) < 0.0f){
-            //printf("here1!\n");
             tangentV1 = tangentV1  * -1.0f;
         }
 
         if (biTangentV2.dotProduct(normalV2.crossProduct(tangentV2)) < 0.0f){
-            //printf("here2!\n");
             tangentV2 = tangentV2  * -1.0f;
         }
 

+ 7 - 8
src/model.cpp

@@ -1,3 +1,9 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-03
+// ===============================
+
+//Headers
 #include "model.h"
 
 Mesh * Model::getMesh(){
@@ -5,35 +11,28 @@ Mesh * Model::getMesh(){
 }
 
 void Model::update(){
-    //You'd get physics updates or user input updates or whatever here
     //Recalculate model matrix for movement or scaling
     mBounds.update(mModelMatrix);
 }
-
 AABox *Model::getBounds(){
     return &mBounds;
 }
-
 Matrix4 *Model::getModelMatrix(){
     return &mModelMatrix;
 }
-
+//Texture getters
 Texture *Model::getAlbedo(){
     return &mAlbedo;
 }
-
 Texture *Model::getNormal(){
     return &mNormal;
 }
-
 Texture *Model::getAO(){
     return &mAmbient;
 }
-
 Texture *Model::getRoughness(){
     return &mRoughness;
 }
-
 Texture *Model::getMetallic(){
     return &mMetallic;
 }

+ 6 - 0
src/objParser.cpp

@@ -1,3 +1,9 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-14
+// ===============================
+
+//Headers
 #include "objParser.h"
 
 Mesh& OBJ::buildMeshFromFile(Mesh &mesh, std::string path){

+ 32 - 11
src/rasterizer.cpp

@@ -1,9 +1,13 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-03
+// ===============================
+
+//Includes
 #include "rasterizer.h"
-#include "vector"
-#include "array"
 #include <algorithm>
 
-//Gamma correction lookup table
+//Gamma correction lookup table, much much faster than actually calculating it
 const int Rasterizer::gammaTable[256] = {0, 21, 28, 34, 39, 43, 46,
         50, 53, 56, 59, 61, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84,
         85, 87, 89, 90, 92, 93, 95, 96, 98, 99, 101, 102, 103, 105, 106,
@@ -32,6 +36,8 @@ const Uint32 Rasterizer::red(SDL_MapRGBA(mappingFormat, 0xFF,0x00,0x00,0xFF));
 const Uint32 Rasterizer::green(SDL_MapRGBA(mappingFormat, 0x00,0xFF,0x00,0xFF));
 const Uint32 Rasterizer::blue(SDL_MapRGBA(mappingFormat, 0x00,0x00,0xFF,0xFF));
 
+
+//Early pixel buffer traversal test
 void Rasterizer::makeCoolPattern(Buffer<Uint32> *pixelBuffer){
     for(int y = 0; y < pixelBuffer->mHeight; ++y){
         for(int x = 0; x < pixelBuffer->mWidth; ++x){
@@ -100,7 +106,13 @@ void Rasterizer::drawWireFrame(Vector3f *vertices, IShader &shader, Buffer<Uint3
     drawLine(vertices[0], vertices[2], blue, pixelBuffer);
 }  
 
-//Draws triangles
+//Candidate for future total overhaul into a SIMD function
+//Why not now? Before doing this I have to do:
+//1.vectorize: Shader, vector3 class rewrite
+//2.Edge detection
+//3.Fixed point rewrite
+//4.SDL function rewrite
+//5.Zbuffer rewrite
 void Rasterizer::drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint32> *pixelBuffer, Buffer<float> *zBuffer){
     //Per triangle variables
     float area;
@@ -142,8 +154,14 @@ void Rasterizer::drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint3
         e.z = e_row.z;
 
         for(int x = xMin; x <= xMax; ++x){
-            //Only draw if inside pixel and following top left rule
+
+            //Originally I followed top left rule to avoid edge rewrites but it was
+            //costing me more to perform this check every pixel than just allowing the rewrite
+            //It's saved in case the pixel shader gets more complex and the tradeoff becomes
+            //worth it
             // if(inside(e.x, A01, B01) && inside(e.y, A12, B12) && inside(e.z, A20, B20) ){
+
+            //Only draw if pixel inside triangle 
             if( (e.x >= 0) && (e.y >= 0 ) && (e.z >= 0 )){
 
                 //Zbuffer check
@@ -159,12 +177,12 @@ void Rasterizer::drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint3
 
                     //Run fragment shader (U, v are barycentric coords)
                     rgbVals = shader.fragment(uPers , vPers);
+
                     //Update pixel buffer with clamped values 
                     (*pixelBuffer)(x,y) = SDL_MapRGB(mappingFormat,
-                    gammaAdjust(rgbVals.data[0]), //
-                    gammaAdjust(rgbVals.data[1]),//
-                    gammaAdjust(rgbVals.data[2]));//
-                    //(*pixelBuffer)(x,y) = SDL_MapRGB(mappingFormat,0xFF, 0xFF, 0xFF);
+                                                gammaAdjust(rgbVals.data[0]), 
+                                                gammaAdjust(rgbVals.data[1]),
+                                                gammaAdjust(rgbVals.data[2]));
                 }   
             }
 
@@ -183,6 +201,7 @@ void Rasterizer::drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint3
 
 void Rasterizer::viewportTransform(Buffer<Uint32> *pixelBuffer, Vector3f *vertices){
     for(int i = 0; i < 3; ++i){
+        //Adding half a pixel to avoid gaps on small vertex values
         vertices[i].x = ((vertices[i].x + 1 ) * pixelBuffer->mWidth * 0.5)  + 0.5;
         vertices[i].y = ((vertices[i].y + 1 ) * pixelBuffer->mHeight * 0.5) + 0.5;
     }
@@ -190,7 +209,7 @@ void Rasterizer::viewportTransform(Buffer<Uint32> *pixelBuffer, Vector3f *vertic
 
 void Rasterizer::triBoundBox(int &xMax, int &xMin, int &yMax, int &yMin,Vector3f *vertices, Buffer<Uint32> *pixelBuffer){
     // xMax = std::ceil(std::max({vertices[0].x, vertices[1].x, vertices[2].x}));
-    //xMin = std::ceil(std::min({vertices[0].x, vertices[1].x, vertices[2].x}));
+    // xMin = std::ceil(std::min({vertices[0].x, vertices[1].x, vertices[2].x}));
     xMax = std::max({vertices[0].x, vertices[1].x, vertices[2].x});
     xMin = std::min({vertices[0].x, vertices[1].x, vertices[2].x});
 
@@ -210,7 +229,7 @@ void Rasterizer::triBoundBox(int &xMax, int &xMin, int &yMax, int &yMin,Vector3f
 float Rasterizer::edge(Vector3f &a, Vector3f &b, Vector3f &c){
     return (b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x);
 }
-
+//Doing this check was slower than allowing overwrites on certain triangle edges so it's
 bool Rasterizer::inside(float e, float a, float b){
     if ( e > 0 )  return true;
     if ( e < 0 )  return false;
@@ -224,6 +243,8 @@ float Rasterizer::clamp(float n, float lower, float upper) {
   return std::max(lower, std::min(n, upper));
 }
 
+//Gamma adjustment table precalculated for a 2.2 gamma value
+//signficant ms gains from this!!
 int Rasterizer::gammaAdjust(float n) {
     int val = round(clamp(n*255, 0, 255));
     return gammaTable[val];

+ 16 - 8
src/renderManager.cpp

@@ -1,10 +1,17 @@
-#include "renderManager.h"
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-02
+// ===============================
 
+//Includes
+#include "renderManager.h"
 
 //Dummy constructors / Destructors
 RenderManager::RenderManager(){}
 RenderManager::~RenderManager(){}
 
+//Sets the internal pointers to the screen and the current scene and inits the software
+//renderer instance. 
 bool RenderManager::startUp(DisplayManager &displayManager,SceneManager &sceneManager ){
     screen = &displayManager;
     sceneLocator = &sceneManager;
@@ -22,23 +29,24 @@ void RenderManager::shutDown(){
 }
 
 void RenderManager::render(){
-    //Clear screen and reset current buffers
-    screen->clear();
+    //Reset current buffers
     renderInstance.clearBuffers();
 
     //Build a render Queue for drawing multiple models
     //Also assigns the current camera to the software renderer
+    //And gets info on the number of lights in the scene
     buildRenderQueue();
 
-    //Draw all meshes in the render queue so far we assume they are
-    //normal triangular meshes.
+    //Draw all meshes in the render queue. So far we assume they are
+    //normal triangular meshes. But it could easily be changed to invoke
+    //different methods based on different model types.
     while( !renderObjectQueue->empty() ){
         renderInstance.drawTriangularMesh(renderObjectQueue->front());
         renderObjectQueue->pop();
     }
 
-    //Swapping pixel buffer with final rendered image with the
-    //display buffer
+    //Drawing to the screen by swapping the window's surface with the 
+    //final buffer containing all rendering information
     screen->swapBuffers(renderInstance.getRenderTarget());
 
     //Set camera pointer to null just in case a scene change occurs
@@ -58,7 +66,7 @@ void RenderManager::buildRenderQueue(){
     //Update the pointer to the list of lights in the scene
     renderInstance.setSceneLights(currentScene->getCurrentLights(), currentScene->getLightCount() );
 
-    //Get pointers to the visible model queu
+    //Get pointers to the visible model queue
     renderObjectQueue = currentScene->getVisiblemodels();
 }
 

+ 79 - 62
src/scene.cpp

@@ -1,3 +1,9 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-10
+// ===============================
+
+//Headers
 #include "scene.h"
 #include "objParser.h"
 #include <fstream>
@@ -5,19 +11,17 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
-//For now a scene only contains a single model
 Scene::Scene(const std::string &sceneName){
     //Building all the useful path strings
     std::string folderPath = "../scenes/" + sceneName;
     std::string baseFilePath = folderPath + "/" + sceneName;
     
     if( !findSceneFolder(folderPath)){
-        //If you do not find the scene folder quit early and gracefully
+        //If you do not find the scene folder quit
         emptyScene = true; 
     }
     else{
-        //Load all cameras, models and lights and return false if it failed
-        //to load anything
+        //Load all cameras, models and lights and return false if it fails
         emptyScene = !loadContent(baseFilePath, sceneName);
     }
 }
@@ -32,6 +36,7 @@ Scene::~Scene(){
     }
 }
 
+//Update Order is critical for correct culling
 void Scene::update(unsigned int deltaT){
     mainCamera.update(deltaT);
     for(Model *models : modelsInScene){
@@ -39,72 +44,37 @@ void Scene::update(unsigned int deltaT){
     }
     frustrumCulling();
 }
-
-//Returns false if there was any issue loading the scene object
-void Scene::loadSceneModel(const std::string &baseFilePath, const TransformParameters &init){
-    std::string meshFilePath = baseFilePath + "_mesh.obj";
-    if(!OBJ::fileExists(meshFilePath)){
-        printf("Error! Mesh: %s does not exist.\n",meshFilePath.c_str());
-    }
-    else{
-        printf( "%s is a valid mesh\n", meshFilePath.c_str() );
-        modelsInScene.push_back(new Model(baseFilePath, init));
-    }
-}
-
-void Scene::frustrumCulling(){
-    for(Model *model : modelsInScene){
-
-        bool visible = mainCamera.checkVisibility(model->getBounds());
-
-        if (visible) {
-            visibleModels.push(model);
-        }
-    }
-}
-
+//-----------------------------GETTERS----------------------------------------------
 std::queue<Model*>* Scene::getVisiblemodels(){
     return &visibleModels;
 }
-
+Camera* Scene::getCurrentCamera(){
+    return &mainCamera;
+}
 BaseLight * Scene::getCurrentLights(){
     return lights;
 }
-
-
-
-Camera* Scene::getCurrentCamera(){
-    return &mainCamera;
+int Scene::getLightCount(){
+    return lightCount;
 }
+//----------------------------------------------------------------
 
 bool Scene::checkIfEmpty(){
     return emptyScene;
 }
 
-bool Scene::findSceneFolder(const std::string &scenePath){
-    struct stat info;
-    if( stat( scenePath.c_str(), &info ) != 0 ){
-        printf( "cannot access %s\n", scenePath.c_str() );
-         return false;
-    }
-    else if( info.st_mode & S_IFDIR ){
-        printf( "%s is a valid scene\n", scenePath.c_str() );
-        return true;
-    }
-    else{
-        printf("Error! Scene: %s does not exist.\n",scenePath.c_str());
-        return false;
-    }
-}
+//-----------------------------SCENE LOADING-----------------------------------
 
+//TODO: separate into new class or function
+//Config file parsing, gets all the important 
 bool Scene::loadContent(const std::string &baseFilePath, const std::string &sceneName ){
     std::string configFilePath = baseFilePath + "_config.txt";
     std::ifstream file(configFilePath.c_str());
     TransformParameters initParameters;
 
-    //Does config file parsing here
-    //TODO: separate into new class or function
+    //Begin config file parsing
     if(!file.good()){
+        //Check config file exists
         printf("Error! Config: %s does not exist.\n",configFilePath.c_str());
         return false;
     }
@@ -121,6 +91,7 @@ bool Scene::loadContent(const std::string &baseFilePath, const std::string &scen
         else{
             iss >> key;
             if(key != sceneName){
+                //Checks the config file belongs to the correct scene
                 printf("Error! Config file: %s does not belong to current scene.\n",configFilePath.c_str());
                 return false;
             }
@@ -130,7 +101,8 @@ bool Scene::loadContent(const std::string &baseFilePath, const std::string &scen
                     std::getline(file,line);
                     std::istringstream iss(line);
                     iss >> key;
-                    if(key == "m"){ //model related setup
+                    //MODEL SETUP
+                    if(key == "m"){ 
                         printf("Loading models...\n");
                         iss >> key;
                         int max = stoi(key);
@@ -161,14 +133,15 @@ bool Scene::loadContent(const std::string &baseFilePath, const std::string &scen
                             std::getline(file,line);
                             
                             //Attempts to load model with the initparameters it has read
-                            //if it fails it won't do anything much now 
                             loadSceneModel(baseFilePath, initParameters);
                         }
                     }
-                    else if(key == "l"){ //light related setup
+                    //LIGHT SETUP
+                    else if(key == "l"){ 
                         printf("Loading lights...\n");
                         iss >> key;
                         lightCount = stoi(key);
+                        //Initializes light array
                         lights = new BaseLight[lightCount];
                         for(int i = 0; i < lightCount; ++i){
 
@@ -189,15 +162,9 @@ bool Scene::loadContent(const std::string &baseFilePath, const std::string &scen
 
                             //Burning empty line that makes the config easier to read
                             std::getline(file,line);
-                            
                         }
                     }
-                    else if(key == "c"){ //camera related setup
-                        printf("Loading camera...\n");
-                        //TODO: camera initialization setup
-                    }
                 }
-
                 //Lastly we check if the scene is empty and return 
                 return !modelsInScene.empty();       
             }
@@ -205,6 +172,56 @@ bool Scene::loadContent(const std::string &baseFilePath, const std::string &scen
     }
 }
 
-int Scene::getLightCount(){
-    return lightCount;
+bool Scene::findSceneFolder(const std::string &scenePath){
+    struct stat info;
+    //folder is blocking access
+    if( stat( scenePath.c_str(), &info ) != 0 ){
+        printf( "cannot access %s\n", scenePath.c_str() );
+         return false;
+    }
+    else if( info.st_mode & S_IFDIR ){
+        //Folder is accessible
+        printf( "%s is a valid scene\n", scenePath.c_str() );
+        return true;
+    }
+    else{
+        //Folder does not exist
+        printf("Error! Scene: %s does not exist.\n",scenePath.c_str());
+        return false;
+    }
 }
+
+void Scene::loadSceneModel(const std::string &baseFilePath, const TransformParameters &init){
+    std::string meshFilePath = baseFilePath + "_mesh.obj";
+    if(!OBJ::fileExists(meshFilePath)){
+        //If the mesh deos not exist it's very likely nothing else does, quit early
+        printf("Error! Mesh: %s does not exist.\n",meshFilePath.c_str());
+    }
+    else{
+        printf( "%s is a valid mesh\n", meshFilePath.c_str() );
+        modelsInScene.push_back(new Model(baseFilePath, init));
+    }
+}
+
+//-------------------------------------------------------------
+
+void Scene::frustrumCulling(){
+    for(Model *model : modelsInScene){
+        bool visible = mainCamera.checkVisibility(model->getBounds());
+        if (visible) {
+            visibleModels.push(model);
+        }
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+

+ 19 - 6
src/sceneManager.cpp

@@ -1,9 +1,18 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-10
+// ===============================
+
+//Headers
 #include "sceneManager.h"
 
 //Dummy constructors / destructors
 SceneManager::SceneManager(){}
 SceneManager::~SceneManager(){}
 
+//Starts up the scene manager and loads the default scene 
+//If for whatever reason the scene could not load any model, or there are none defined
+//It just quits early.
 bool SceneManager::startUp(){
     currentSceneID = "teapot";
     if (!loadScene(currentSceneID)){
@@ -17,6 +26,8 @@ void SceneManager::shutDown(){
     delete currentScene;
 }
 
+//Checks if the scene that you want to load is not the one that is currently loaded.
+// If it isn't, then it deletes the current one and loads the new one.
 bool SceneManager::switchScene(std::string newSceneID){
     if( newSceneID != currentSceneID ){
         currentSceneID = newSceneID;
@@ -29,16 +40,18 @@ bool SceneManager::switchScene(std::string newSceneID){
     }
 }
 
-//Loads the given scene and all related textures
-bool SceneManager::loadScene(std::string sceneID){
-    currentScene = new Scene(sceneID);
-    return  !currentScene->checkIfEmpty(); //True if empty, so it's negated for startup
-}
-
+//Misdirection towards the current scene to avoid pointer dangling after scene switching
 void SceneManager::update(unsigned int deltaT){
     currentScene->update(deltaT);
 }
 
 Scene* SceneManager::getCurrentScene(){
     return currentScene;
+}
+
+//Loads the scene with the given ID. If the scene is empty it will declare it an unsuccesful
+//load and attempt to quit early of the whole program
+bool SceneManager::loadScene(std::string sceneID){
+    currentScene = new Scene(sceneID);
+    return  !currentScene->checkIfEmpty(); //True if empty, so it's negated for startup
 }

+ 42 - 30
src/softwareRenderer.cpp

@@ -1,8 +1,15 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-10
+// ===============================
+
+//Headers
 #include "softwareRenderer.h"
 #include "shader.h"
 #include "mesh.h"
 #include "omp.h"
 
+//Dummy Constructor / Destructor
 SoftwareRenderer::SoftwareRenderer(){}
 SoftwareRenderer::~SoftwareRenderer(){}
 
@@ -10,13 +17,16 @@ bool SoftwareRenderer::startUp(int w, int h){
     if( !createBuffers(w, h) ){
         return false;
     }
+    //Want to make sure that we don't call for a delete of zbuffer and pixelbuffer
+    //Unless the startup has been complete
     startUpComplete = true;
-    return true;
+    return startUpComplete;
 }
 
 void SoftwareRenderer::shutDown(){
     mLights = nullptr;
     mCamera = nullptr;
+    //Only delete buffers if startup completed successfully
     if (startUpComplete){
         delete zBuffer;
         delete pixelBuffer;
@@ -24,7 +34,7 @@ void SoftwareRenderer::shutDown(){
 }
 
 void SoftwareRenderer::drawTriangularMesh(Model * currentModel){
-    //Getting the vertices, faces, texture data 
+    //Getting the vertices, faces, normals and texture data for the whole model
     Mesh *triMesh = currentModel->getMesh();
     std::vector<Vector3i> * vIndices = &triMesh->vertexIndices;
     std::vector<Vector3i> * tIndices = &triMesh->textureIndices;
@@ -37,10 +47,6 @@ void SoftwareRenderer::drawTriangularMesh(Model * currentModel){
     std::vector<Vector3f> * tangents = &triMesh->tangents;
     int numFaces = triMesh->numFaces;
 
-    //Array grouping vertices together into triangle
-    Vector3f trianglePrimitive[3], normalPrim[3], uvPrim[3],
-             tangentPrim[3];
-
     //Initializing shader textures
     PBRShader shader;
     shader.albedoT   = currentModel->getAlbedo();
@@ -63,47 +69,51 @@ void SoftwareRenderer::drawTriangularMesh(Model * currentModel){
     shader.V   = (mCamera->viewMatrix);
     shader.M   = *(currentModel->getModelMatrix());
     shader.N   = (shader.M.inverse()).transpose(); 
-    shader.cameraPos = mCamera->position;
 
+    shader.cameraPos = mCamera->position;
     shader.numLights  = mNumLights;
     shader.lightCol   = lColor;
-    shader.lightPos = lightPositions;
+    shader.lightPos   = lightPositions;
 
     //Building worldToObject matrix
     Matrix4 worldToObject = (*(currentModel->getModelMatrix())).inverse();
 
-    // Iterate through every triangle
-    int count = 0;
-    Vector3f dummyDir; //TO DO FIX THIS
-
-    #pragma omp parallel for private(trianglePrimitive, normalPrim, uvPrim, tangentPrim) firstprivate(shader) schedule(dynamic)
+    //Iterate through every triangle on mesh with early quiting by backface culling
+    //It also uses dynamic scheduling since on average 50% of the threads would finish early
+    //because of backface culling. This allows for redistributing of parallel tasks between
+    //threads to increase parallelization effectiveness.
+    #pragma omp parallel for firstprivate(shader) schedule(dynamic)
     for (int j= 0; j < numFaces; ++j){
-        Vector3f lightDir[mNumLights * 3 ];
-        shader.lightDirVal = lightDir;
-        //Current vertex and normal indices
+        //Arrays used to group vertices together into triangles
+        Vector3f trianglePrimitive[3], normalPrim[3], uvPrim[3],
+             tangentPrim[3];
+
+        //Current vertex, normals and texture data indices
         Vector3i f = (*vIndices)[j];
         Vector3i n = (*nIndices)[j];
         Vector3i u = (*tIndices)[j];
 
-        //Pack vertex, normal and UV data into arrays
-        buildTri(f, trianglePrimitive, *vertices);
-        buildTri(n, normalPrim, *normals);
-        buildTri(u, uvPrim, *texels);
-        buildTri(f, tangentPrim, *tangents);
+        //Last setup of shader light variables
+        Vector3f lightDir[mNumLights * 3 ];
+        shader.lightDirVal = lightDir;    
+
+        //Pack vertex, normal and UV data into triangles
+        packDataIntoTris(f, trianglePrimitive, *vertices);
+        packDataIntoTris(n, normalPrim, *normals);
+        packDataIntoTris(u, uvPrim, *texels);
+        packDataIntoTris(f, tangentPrim, *tangents);
 
         //Early quit if face is pointing away from camera
         if (backFaceCulling((*fNormals)[j], trianglePrimitive[0], worldToObject)) continue;
-        ++count;
+
         //Apply vertex shader
         for(int i = 0; i < 3; ++i){
-            trianglePrimitive[i] = shader.vertex(
-                trianglePrimitive[i], normalPrim[i],
-                uvPrim[i], tangentPrim[i], 
-                dummyDir, i);
+            trianglePrimitive[i] = shader.vertex(trianglePrimitive[i], normalPrim[i],
+                                                uvPrim[i], tangentPrim[i], i);
         }
 
         //Skip triangles that are outside viewing frustrum
-        //Does not rebuild triangles that are partially out TO DO
+        //Does not rebuild triangles that are only partially out
         if (clipTriangles(trianglePrimitive)) continue;
 
         perspectiveDivide(trianglePrimitive);
@@ -113,9 +123,9 @@ void SoftwareRenderer::drawTriangularMesh(Model * currentModel){
         Rasterizer::drawTriangles(trianglePrimitive, shader, pixelBuffer, zBuffer);
         
     }
-    //printf("%d faces drawn.\n", count);
 }
 
+//Candidate to be refactored out into render manager
 void SoftwareRenderer::clearBuffers(){
     zBuffer->clear();
     pixelBuffer->clear();
@@ -129,7 +139,6 @@ void SoftwareRenderer::setCameraToRenderFrom(Camera * camera){
     mCamera = camera;
 }
 
-
 void SoftwareRenderer::setSceneLights(BaseLight * lights, int numLights){
     mNumLights = numLights;
     mLights = lights;
@@ -155,12 +164,14 @@ bool SoftwareRenderer::createBuffers(int w, int h){
     return success;
 }
 
-void SoftwareRenderer::buildTri(Vector3i &index, Vector3f *primitive, std::vector<Vector3f> &vals){
+void SoftwareRenderer::packDataIntoTris(Vector3i &index, Vector3f *primitive, std::vector<Vector3f> &vals){
     for(int i = 0; i < 3; ++i){
         primitive[i] = vals[index.data[i]];
     }
 }
 
+//Gets view direction in object space and uses it to check if the facet normal
+//Is aligned with the viewdirection
 bool SoftwareRenderer::backFaceCulling(Vector3f &facetNormal, Vector3f &vert,  Matrix4 &worldToObject){
         Vector3f viewDir =  worldToObject.matMultVec(mCamera->position) -  vert;
         viewDir.normalized();
@@ -170,6 +181,7 @@ bool SoftwareRenderer::backFaceCulling(Vector3f &facetNormal, Vector3f &vert,  M
         return intensity <= 0.0;
 }
 
+//Inside bounds described in perspective matrix calculation
 bool SoftwareRenderer::clipTriangles(Vector3f *clipSpaceVertices){
     int count = 0;
     for(int i = 0; i < 3; ++i){

+ 15 - 8
src/texture.cpp

@@ -1,8 +1,16 @@
+// ===============================
+// AUTHOR       : Angel Ortiz (angelo12 AT vt DOT edu)
+// CREATE DATE  : 2018-07-02
+// ===============================
+
+//Headers
 #include "texture.h"
 #define STB_IMAGE_IMPLEMENTATION
 #include "stb_image.h"
 #include <cmath>
 
+//Depending on the type of texture the data that is loaded must be 
+//transformed in different ways. 
 Texture::Texture(std::string path, std::string type){
     stbi_set_flip_vertically_on_load(true);  
 
@@ -11,19 +19,19 @@ Texture::Texture(std::string path, std::string type){
     pixelData = new float[width*height*channels];
 
     if (data){
-        if(type == "RGB"){
+        if(type == "RGB"){ //Rgb data requires a gamma correction, float conversion
             for(int i = 0; i < width*height*channels; ++i){
                 pixelData[i] = std::pow((float)data[i] * (1/255.0f), 2.2f);
             }
             tileData();
         }
-        else if (type == "XYZ"){
+        else if (type == "XYZ"){//conversion to float and rescaling to -1 1 bounds
             for(int i = 0; i < width*height*channels; ++i){
                 pixelData[i] = (float)data[i] * (2/255.0f) - 1.0f;
             }
             tileData();
         }
-        else if (type == "BW"){
+        else if (type == "BW"){ //Simple conversion to float
             for(int i = 0; i < width*height*channels; ++i){
                 pixelData[i] = (float)data[i] * (1/255.0f);
             }
@@ -39,6 +47,8 @@ Texture::Texture(std::string path, std::string type){
     stbi_image_free(data);
 }
 
+//Organizes the texture images in tiles to improve cache coherency
+//and reduce the amount of cache misses that getting pixel values would cause
 void Texture::tileData(){
     float *tiledPixelData = new float[width*height*channels];
 
@@ -84,10 +94,10 @@ Texture::~Texture(){
     delete [] pixelData;
 }
 
+//Tiling has invalidated my bilinear filtering code but it is here for posterity
 Vector3f Texture::getPixelVal(float u, float v){
 
     //Simple bilinear filtering
-    //DISABLED FOR NOW since it trashes the FPS
     // float intU;
     // float tU = std::modf(u * (width-1), &intU);
     // int uIntLo = (int)intU; 
@@ -124,9 +134,7 @@ Vector3f Texture::getPixelVal(float u, float v){
     int inTileY = vInt % tileH;
 
     int index = ((tileY * widthInTiles + tileX) * (tileW * tileH)
-                + inTileY * tileW
-                + inTileX)*channels;
-
+                + inTileY * tileW + inTileX)*channels;
 
     return Vector3f{pixelData[index], pixelData[index+1], pixelData[index+2]};
 
@@ -134,7 +142,6 @@ Vector3f Texture::getPixelVal(float u, float v){
 
 float Texture::getIntensityVal(float u, float v){
     //Simple bilinear filtering
-    //DISABLED FOR NOW since it trashes the FPS
     // float intU;
     // float tU = std::modf(u * (width-1), &intU);
     // int uIntLo = (int)intU;