1 /**
2  * Defines the Mesh class, which controls all meshes loaded into the world.
3  */
4 module components.mesh;
5 
6 import core.properties;
7 import components.component;
8 import graphics.graphics, graphics.shaders;
9 import utility.output;
10 
11 import derelict.assimp3.assimp;
12 import derelict.opengl3.gl3;
13 
14 import std.stdio, std.stream, std.format, std.math;
15 
16 class Mesh : Component
17 {
18 public:
19 	mixin Property!( "uint", "glVertexArray", "protected" );
20 	mixin Property!( "uint", "numVertices", "protected" );
21 	mixin Property!( "uint", "numIndices", "protected" );
22 	mixin BackedProperty!( "uint", "_glIndexBuffer", "glIndexBuffer" );
23 	mixin BackedProperty!( "uint", "_glVertexBuffer", "glVertexBuffer" );
24 	enum FloatsPerVertex = 11;
25 	enum VertexSize = float.sizeof * FloatsPerVertex;
26 
27 	this( string filePath )
28 	{
29 		super( null );
30 
31 		// Initial assimp start
32 		DerelictASSIMP3.load();
33 
34 		// Load the scene via assimp
35 		const aiScene* scene = aiImportFile(( filePath ~ "\0" ).ptr,
36 											aiProcess_CalcTangentSpace | aiProcess_Triangulate | 
37 											aiProcess_JoinIdenticalVertices | aiProcess_SortByPType );//|
38 											//aiProcess_FlipWindingOrder );
39 		float[] outputData;
40 		uint[] indices;
41 		if(!scene)
42 		{
43 			// Did not load
44 			log( OutputType.Error, "Mesh not loaded: ", filePath );
45 		}
46 		else
47 		{
48 			// Get the mesh
49 			auto mesh = scene.mMeshes[0];
50 
51 			// For each vertex on each face
52  			int meshFaces = mesh.mNumFaces;
53 			for( int i = 0; i < meshFaces; i++ )
54 			{
55 				auto face = mesh.mFaces[i];
56 				for( int j = 0; j < 3; j++ )
57 				{
58 					// Get the vertex data
59 					aiVector3D pos = mesh.mVertices[ face.mIndices[ j ] ];
60 					aiVector3D uv = mesh.mTextureCoords[ 0 ][ face.mIndices[ j ] ];
61 					aiVector3D normal = mesh.mNormals[ face.mIndices[ j ] ];
62 					aiVector3D tangent = mesh.mTangents[ face.mIndices[ j ] ];
63 					aiVector3D bitangent = mesh.mBitangents[ face.mIndices[ j ] ];
64 
65 					// Append the data
66 					outputData ~= pos.x;
67 					outputData ~= pos.y;
68 					outputData ~= pos.z;
69 					outputData ~= uv.x;
70 					outputData ~= uv.y;
71 					outputData ~= normal.x;
72 					outputData ~= normal.y;
73 					outputData ~= normal.z;
74 					outputData ~= tangent.x;
75 					outputData ~= tangent.y;
76 					outputData ~= tangent.z;
77 					//outputData ~= bitangent.x;
78 					//outputData ~= bitangent.y;
79 					//outputData ~= bitangent.z;
80 				}
81 			}
82 
83 			numVertices = cast(uint)( outputData.length / FloatsPerVertex );  // 11 is num floats per vertex
84 			numIndices = numVertices;
85 
86 			indices = new uint[ numIndices ];
87 			foreach( ii; 0..numIndices )
88 				indices[ ii ] = ii;
89 		}
90 		// Release assimp instance now that we have all the model data
91 		aiReleaseImport( scene );
92 
93 		
94 		// make and bind the VAO
95 		glGenVertexArrays( 1, &_glVertexArray );
96 		glBindVertexArray( glVertexArray );
97 
98 		// make and bind the VBO
99 		glGenBuffers( 1, &_glVertexBuffer );
100 		glBindBuffer( GL_ARRAY_BUFFER, glVertexBuffer );
101 
102 		// Buffer the data
103 		glBufferData( GL_ARRAY_BUFFER, outputData.length * GLfloat.sizeof, outputData.ptr, GL_STATIC_DRAW );
104 
105 		uint POSITION_ATTRIBUTE = 0;
106 		uint UV_ATTRIBUTE = 1;
107 		uint NORMAL_ATTRIBUTE = 2;
108 		uint TANGENT_ATTRIBUTE = 3;
109 		uint BINORMAL_ATTRIBUTE = 4;
110 
111 		// Connect the position to the inputPosition attribute of the vertex shader
112 		glEnableVertexAttribArray( POSITION_ATTRIBUTE );
113 		glVertexAttribPointer( POSITION_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, VertexSize, cast(const(void)*)0 );
114 		// Connect uv to the textureCoordinate attribute of the vertex shader
115 		glEnableVertexAttribArray( UV_ATTRIBUTE );
116 		glVertexAttribPointer( UV_ATTRIBUTE, 2, GL_FLOAT, GL_FALSE, VertexSize, cast(char*)0 + ( GLfloat.sizeof * 3 ) );
117 		// Connect normals to the shaderPosition attribute of the vertex shader
118 		glEnableVertexAttribArray( NORMAL_ATTRIBUTE );
119 		glVertexAttribPointer( NORMAL_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, VertexSize, cast(char*)0 + ( GLfloat.sizeof * 5 ) );
120 		// Connect the tangent to the vertex shader
121 		glEnableVertexAttribArray( TANGENT_ATTRIBUTE );
122 		glVertexAttribPointer( TANGENT_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, VertexSize, cast(char*)0 + ( GLfloat.sizeof * 8 ) );
123 		// Connect the binormal to the vertex shader
124 		//glEnableVertexAttribArray( BINORMAL_ATTRIBUTE );
125 		//glVertexAttribPointer( BINORMAL_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, VertexSize, cast(char*)0 + ( GLfloat.sizeof * 11 ) );
126 
127 		// Generate index buffer
128 		glGenBuffers( 1, &_glIndexBuffer );
129 		glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, glIndexBuffer );
130 
131 		// Buffer index data
132 		glBufferData( GL_ELEMENT_ARRAY_BUFFER, uint.sizeof * numVertices, indices.ptr, GL_STATIC_DRAW );
133 
134 		// unbind the VBO and VAO
135 		glBindBuffer( GL_ARRAY_BUFFER, 0 );
136 		glBindVertexArray( 0 );
137 	}
138 
139 	override void update()
140 	{
141 
142 	}
143 
144 	override void shutdown()
145 	{
146 		glDeleteBuffers( 1, &_glVertexBuffer );
147 		glDeleteBuffers( 1, &_glVertexArray );
148 	}
149 
150 private:
151 	union
152 	{
153 		uint _glIndexBuffer;
154 	}
155 
156 	union
157 	{
158 		uint _glVertexBuffer;
159 	}
160 }