void Primitive::PrimitiveData::GeneratePlane(void) { //Calculate how many vertices/indices are required numIndices = slices * stacks * VERTS_PER_QUAD; indices = new GLuint[numIndices]; int curr_index = 0; numVertices = (slices + 1) * (stacks + 1); vertices = new Vertex[numVertices]; //Create the top row of the plane vertices[0].pos = Vec3(-0.5f, 0.5f, 0); vertices[0].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[0].tex = Vec2(0, 0); vertices[0].nml = Vec3(0, 0, 1.0f); for (int j = 0; j < slices; ++j) { vertices[j + 1].pos = Vec3(static_cast(j + 1) / slices - 0.5f, 0.5f, 0); vertices[j + 1].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[j + 1].tex = Vec2(static_cast(j + 1) / slices, 0); vertices[j + 1].nml = Vec3(0, 0, 1.0f); } for (int i = 0; i < stacks; ++i) { //Calculate common variables int start_index = (i + 1) * (slices + 1); float y = -static_cast(i + 1) / stacks + 0.5f; float v = static_cast(i + 1) / stacks; //Create the first vertex in the row vertices[start_index].pos = Vec3(-0.5f, y, 0); vertices[start_index].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[start_index].tex = Vec2(0, v); vertices[start_index].nml = Vec3(0, 0, 1.0f); for (int j = 0; j < slices; ++j) { //Add the last vertex to complete the current quad, then assign indices float x = static_cast(j + 1) / slices - 0.5f; float u = static_cast(j + 1) / slices; int vertexindex = start_index + j + 1; vertices[vertexindex].pos = Vec3(x, y, 0); vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(u, v); vertices[vertexindex].nml = Vec3(0, 0, 1.0f); indices[curr_index++] = vertexindex - (slices + 1) - 1; indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex - (slices + 1); indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex; indices[curr_index++] = vertexindex - (slices + 1); } } } void Primitive::PrimitiveData::GenerateCube(void) { //Calculate how many vertices/indices are required numIndices = slices * stacks * VERTS_PER_QUAD * CUBE_FACES;; indices = new GLuint[numIndices]; int curr_index = 0; numVertices = (slices + 1) * (stacks + 1) * CUBE_FACES; vertices = new Vertex[numVertices]; int verts_per_face = (slices + 1) * (stacks + 1); //Generate the first face //Create the top row of the plane vertices[0].pos = Vec3(-0.5f, 0.5f, 0.5f); vertices[0].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[0].tex = Vec2(0, 0); vertices[0].nml = Vec3(0, 0, 1.0f); for (int j = 0; j < slices; ++j) { vertices[j + 1].pos = Vec3(static_cast(j + 1) / slices - 0.5f, 0.5f, 0.5f); vertices[j + 1].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[j + 1].tex = Vec2(static_cast(j + 1) / slices, 0); vertices[j + 1].nml = Vec3(0, 0, 1.0f); } for (int i = 0; i < stacks; ++i) { //Calculate common variables int start_index = (i + 1) * (slices + 1); float y = -static_cast(i + 1) / stacks + 0.5f; float v = static_cast(i + 1) / stacks; //Create the first vertex in the row vertices[start_index].pos = Vec3(-0.5f, y, 0.5f); vertices[start_index].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[start_index].tex = Vec2(0, v); vertices[start_index].nml = Vec3(0, 0, 1.0f); for (int j = 0; j < slices; ++j) { //Add the last vertex to complete the current quad, then assign indices float x = static_cast(j + 1) / slices - 0.5f; float u = static_cast(j + 1) / slices; int vertexindex = start_index + j + 1; vertices[vertexindex].pos = Vec3(x, y, 0.5f); vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(u, v); vertices[vertexindex].nml = Vec3(0, 0, 1.0f); indices[curr_index++] = vertexindex - (slices + 1) - 1; indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex - (slices + 1); indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex; indices[curr_index++] = vertexindex - (slices + 1); } } //Generate all other faces from the first face Mtx44 m; for (int k = 1; k < CUBE_FACES; ++k) { //Calculate the rotation matrix switch (k) { case 1: m = m.Rotate(0, 1.0f, 0, PI / 2); break; case 2: m = m.Rotate(0, 1.0f, 0, PI); break; case 3: m = m.Rotate(0, 1.0f, 0, 3 *PI / 2); break; case 4: m = m.Rotate(1.0f, 0, 0, PI / 2); break; case 5: m = m.Rotate(1.0f, 0, 0, 3 * PI / 2); break; } int face_index = k * verts_per_face; //Create the top row of the plane vertices[face_index].pos = m * Vec4(vertices[0].pos, 1); vertices[face_index].col = vertices[0].col; vertices[face_index].tex = vertices[0].tex; vertices[face_index].nml = m * Vec4(vertices[0].nml, 1); for (int j = 0; j < slices; ++j) { vertices[face_index + j + 1].pos = m * Vec4(vertices[j + 1].pos, 1); vertices[face_index + j + 1].col = vertices[j + 1].col; vertices[face_index + j + 1].tex = vertices[j + 1].tex; vertices[face_index + j + 1].nml = m * Vec4(vertices[j + 1].nml, 1); } for (int i = 0; i < stacks; ++i) { //Calculate common variables int start_index = (i + 1) * (slices + 1); //Create the first vertex in the row vertices[face_index + start_index].pos = m * Vec4(vertices[start_index].pos, 1); vertices[face_index + start_index].col = vertices[start_index].col; vertices[face_index + start_index].tex = vertices[start_index].tex; vertices[face_index + start_index].nml = m * Vec4(vertices[start_index].nml, 1); for (int j = 0; j < slices; ++j) { //Add the last vertex to complete the current quad, then assign indices int vertexindex = start_index + j + 1; vertices[face_index + vertexindex].pos = m * Vec4(vertices[vertexindex].pos, 1); vertices[face_index + vertexindex].col = vertices[vertexindex].col; vertices[face_index + vertexindex].tex = vertices[vertexindex].tex; vertices[face_index + vertexindex].nml = m * Vec4(vertices[vertexindex].nml, 1); indices[curr_index++] = face_index + vertexindex - (slices + 1) - 1; indices[curr_index++] = face_index + vertexindex - 1; indices[curr_index++] = face_index + vertexindex - (slices + 1); indices[curr_index++] = face_index + vertexindex - 1; indices[curr_index++] = face_index + vertexindex; indices[curr_index++] = face_index + vertexindex - (slices + 1); } } } } void Primitive::PrimitiveData::GenerateSphere(void) { if (stacks < 2) stacks = 2; //Calculate how many vertices/indices are required numIndices = slices * VERTS_PER_TRI * 2 + (stacks - 2) * slices * VERTS_PER_QUAD; indices = new GLuint[numIndices]; int curr_index = 0; numVertices = 2 * slices + (stacks - 2 + 1) * (slices + 1); vertices = new Vertex[numVertices]; float r = 0.5f; //Create top of sphere int i = 0; { //Create top row for (int j = 0; j < slices; ++j) { vertices[j].pos = Vec3(0.0f, 0.5f, 0.0f); vertices[j].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[j].tex = Vec2(static_cast(j) / slices, 0.0f); vertices[j].nml = vertices[j].pos.Normalize(); } //Create the first in the row float v = 1.0f / stacks; float phi = 1.0f / stacks * PI; vertices[slices].pos = Vec3(sin(phi) * cos(0.0), cos(phi), -sin(phi) * sin(0.0)) * r; vertices[slices].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[slices].tex = Vec2(0.0f, v); vertices[slices].nml = vertices[slices].pos.Normalize(); //Complete the first stack for (int j = 0; j < slices; ++j) { int vertexindex = slices + j + 1; float u = static_cast(j + 1) / slices; float theta = static_cast(j + 1) / slices * 2 * PI; //Add last vertex to current tri, then assign indices vertices[vertexindex].pos = Vec3(sin(phi) * cos(theta), cos(phi), -sin(phi) * sin(theta)) * r; vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(u, v); vertices[vertexindex].nml = vertices[vertexindex].pos.Normalize(); indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex; indices[curr_index++] = j; } } //Create middle for (++i; i < (stacks - 1); ++i) { //Calculate common variables int start_index = (2 * slices + 1) + (i - 1) * (slices + 1); float v = static_cast(i + 1) / stacks; float phi = static_cast(i + 1) / stacks * PI; //Create the first vertex in the row vertices[start_index].pos = Vec3(sin(phi) * cos(0.0), cos(phi), -sin(phi) * sin(0.0)) * r; vertices[start_index].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[start_index].tex = Vec2(0, v); vertices[start_index].nml = vertices[start_index].pos.Normalize(); for (int j = 0; j < slices; ++j) { int vertexindex = start_index + j + 1; float u = static_cast(j + 1) / slices; float theta = static_cast(j + 1) / slices * 2 * PI; //Create the last vertex in the quad, then assign indices vertices[vertexindex].pos = Vec3(sin(phi) * cos(theta), cos(phi), -sin(phi) * sin(theta)) * r; vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(u, v); vertices[vertexindex].nml = vertices[vertexindex].pos.Normalize(); indices[curr_index++] = vertexindex - (slices + 1) - 1; indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex - (slices + 1); indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex; indices[curr_index++] = vertexindex - (slices + 1); } } //Create bottom for (int j = 0; j < slices; ++j) { int vertexindex = numVertices - slices + j; float u = static_cast(j + 1) / slices; float theta = static_cast(j + 1) / slices * 2 * PI; //Add last vertex to current tri, then assign indices vertices[vertexindex].pos = Vec3(sin(PI) * cos(theta), cos(PI), -sin(PI) * sin(theta)) * r; vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(u, 1.0f); vertices[vertexindex].nml = vertices[vertexindex].pos.Normalize(); indices[curr_index++] = vertexindex; indices[curr_index++] = vertexindex - (slices + 1) + 1; indices[curr_index++] = vertexindex - (slices + 1); } } void Primitive::PrimitiveData::GenerateCylinder(void) { if (stacks < 2) stacks = 2; if (slices < 2) slices = 2; //Calculate how many vertices/indices are required numIndices = slices * VERTS_PER_TRI * 2 + stacks * slices * VERTS_PER_QUAD; indices = new GLuint[numIndices]; int curr_index = 0; numVertices = 2 * (2 * slices + 1) + (stacks + 1) * (slices + 1); vertices = new Vertex[numVertices]; float r = 0.5f; //Create top of the cylinder { float y = 0.5f; //Create top row for (int j = 0; j < slices; ++j) { vertices[j].pos = Vec3(0.0f, y, 0.0f); vertices[j].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[j].tex = Vec2(0.5f, 0.5f); vertices[j].nml = Vec3(0.0f, 1.0f, 0.0f); } //Create the first in the second row vertices[slices].pos = Vec3(r, y, 0); vertices[slices].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[slices].tex = Vec2(vertices[slices].pos.x + 0.5f, vertices[slices].pos.z + 0.5f); vertices[slices].nml = Vec3(0.0f, 1.0f, 0.0f); //Complete the top for (int j = 0; j < slices; ++j) { int vertexindex = slices + j + 1; float theta = static_cast(j + 1) / slices * 2 * PI; //Add last vertex to current tri, then assign indices vertices[vertexindex].pos = Vec3(r * cos(theta), y, r * -sin(theta)); vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(vertices[vertexindex].pos.x + 0.5f, vertices[vertexindex].pos.z + 0.5f); vertices[vertexindex].nml = Vec3(0.0f, 1.0f, 0.0f); indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex; indices[curr_index++] = j; } } //Create middle //create the first row { int start_index = 2 * slices + 1; float y = 0.5f; vertices[start_index].pos = Vec3(r, y, 0); vertices[start_index].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[start_index].tex = Vec2(0, 0); vertices[start_index].nml = Vec3(vertices[start_index].pos.x, 0, vertices[start_index].pos.z).Normalize(); for (int j = 0; j < slices; ++j) { int vertexindex = start_index + j + 1; float theta = static_cast(j + 1) / slices * 2 * PI; float u = static_cast(j + 1) / slices; vertices[vertexindex].pos = Vec3(r * cos(theta), y, r * -sin(theta)); vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(u, 0); vertices[vertexindex].nml = Vec3(vertices[vertexindex].pos.x, 0, vertices[vertexindex].pos.z).Normalize(); } } for (int i = 0; i < stacks; ++i) { int start_index = (2 + i) * (slices + 1) + slices; float v = static_cast(i + 1) / stacks; float y = -static_cast(i + 1) / stacks + 0.5f; //Create the first vertex in the row vertices[start_index].pos = Vec3(r * cos(0.0), y, r * -sin(0.0)); vertices[start_index].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[start_index].tex = Vec2(0, v); vertices[start_index].nml = Vec3(vertices[start_index].pos.x, 0, vertices[start_index].pos.z).Normalize(); for (int j = 0; j < slices; ++j) { int vertexindex = start_index + j + 1; float u = static_cast(j + 1) / slices; float theta = static_cast(j + 1) / slices * 2 * PI; //Create the last vertex in the quad and add the indices vertices[vertexindex].pos = Vec3(r * cos(theta), y, r * -sin(theta)); vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(u, v); vertices[vertexindex].nml = Vec3(vertices[vertexindex].pos.x, 0, vertices[vertexindex].pos.z).Normalize(); indices[curr_index++] = vertexindex - (slices + 1) - 1; indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex - (slices + 1); indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex; indices[curr_index++] = vertexindex - (slices + 1); } } //Create bottom of the cylinder { float y = -0.5f; int start_index = numVertices - (2 * slices + 1); //Create bottom row for (int j = 0; j < slices; ++j) { int vertexindex = start_index + j; vertices[vertexindex].pos = Vec3(0.0f, y, 0.0f); vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(0.5f, 0.5f); vertices[vertexindex].nml = Vec3(0.0f, -1.0f, 0.0f); } start_index += slices; //Create the first in the top row vertices[start_index].pos = Vec3(r, y, 0); vertices[start_index].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[start_index].tex = Vec2(-vertices[start_index].pos.x + 0.5f, vertices[start_index].pos.z + 0.5f); vertices[start_index].nml = Vec3(0.0f, -1.0f, 0.0f); //Complete the bottom for (int j = 0; j < slices; ++j) { int vertexindex = start_index + j + 1; float theta = static_cast(j + 1) / slices * 2 * PI; //Add last vertex to current tri, then assign indices vertices[vertexindex].pos = Vec3(r * cos(theta), y, r * -sin(theta)); vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(-vertices[vertexindex].pos.x + 0.5f, vertices[vertexindex].pos.z + 0.5f); vertices[vertexindex].nml = Vec3(0.0f, -1.0f, 0.0f); indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex - (slices + 1); indices[curr_index++] = vertexindex; } } } void Primitive::PrimitiveData::GenerateCone(void) { if (slices < 2) slices = 2; //Calculate how many vertices/indices are required numIndices = 2 * slices * VERTS_PER_TRI + (stacks - 1) * slices * VERTS_PER_QUAD; indices = new GLuint[numIndices]; int curr_index = 0; numVertices = (2 * slices + 1) + (stacks + 1) * (slices + 1) - 1; vertices = new Vertex[numVertices]; //Create top { //Create top row for (int j = 0; j < slices; ++j) { float theta = static_cast(j) / slices * 2 * PI; float u = static_cast(j) / slices; vertices[j].pos = Vec3(0.0f, 0.5f, 0.0f); vertices[j].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[j].tex = Vec2(u, 0); vertices[j].nml = Vec3(cos(theta), 0.5f, -sin(theta)).Normalize(); } //Create the first in the second row float y = -1.0f / stacks + 0.5f; float v = 1.0f / stacks; float r = 1.0f / stacks * 0.5f; vertices[slices].pos = Vec3(r, y, 0); vertices[slices].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[slices].tex = Vec2(0, v); vertices[slices].nml = Vec3(1.0f, 0.5f, 0).Normalize(); //Complete the top for (int j = 0; j < slices; ++j) { int vertexindex = slices + j + 1; float theta = static_cast(j + 1) / slices * 2 * PI; float u = static_cast(j + 1) / slices; //Add last vertex to current tri, then assign indices vertices[vertexindex].pos = Vec3(r * cos(theta), y, r * -sin(theta)); vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(u, v); vertices[vertexindex].nml = Vec3(cos(theta), 0.5f, -sin(theta)).Normalize(); indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex; indices[curr_index++] = j; } } //Create middle for (int i = 1; i < stacks; ++i) { int start_index = (2 * slices + 1) + (i - 1) * (slices + 1); float r = static_cast(i + 1) / stacks * 0.5f; float y = -static_cast(i + 1) / stacks + 0.5f; float v = static_cast(i + 1) / stacks; //Create the first in the new row vertices[start_index].pos = Vec3(r, y,0); vertices[start_index].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[start_index].tex = Vec2(0, v); vertices[start_index].nml = Vec3(1, 0.5f, 0).Normalize(); for (int j = 0; j < slices; ++j) { int vertexindex = start_index + j + 1; float u = static_cast(j + 1) / slices; float theta = static_cast(j + 1) / slices * 2 * PI; //Add the last vertex to the quad and assign indices vertices[vertexindex].pos = Vec3(r * cos(theta), y, r * -sin(theta)); vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(u, v); vertices[vertexindex].nml = Vec3(cos(theta), 0.5f, -sin(theta)).Normalize(); indices[curr_index++] = vertexindex - (slices + 1) - 1; indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex - (slices + 1); indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex; indices[curr_index++] = vertexindex - (slices + 1); } } //Create bottom float r = 0.5f; { float y = -0.5f; int start_index = numVertices - (2 * slices + 1); //Create bottom row for (int j = 0; j < slices; ++j) { int vertexindex = start_index + j; vertices[vertexindex].pos = Vec3(0.0f, y, 0.0f); vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(0.5f, 0.5f); vertices[vertexindex].nml = Vec3(0.0f, -1.0f, 0.0f); } start_index += slices; //Create the first in the top row vertices[start_index].pos = Vec3(r, y, 0); vertices[start_index].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[start_index].tex = Vec2(-vertices[start_index].pos.x + 0.5f, vertices[start_index].pos.z + 0.5f); vertices[start_index].nml = Vec3(0.0f, -1.0f, 0.0f); //Complete the bottom for (int j = 0; j < slices; ++j) { int vertexindex = start_index + j + 1; float theta = static_cast(j + 1) / slices * 2 * PI; //Add last vertex to current tri, then assign indices vertices[vertexindex].pos = Vec3(r * cos(theta), y, r * -sin(theta)); vertices[vertexindex].col = Vec4(1.0f, 1.0f, 1.0f, 1.0f); vertices[vertexindex].tex = Vec2(-vertices[vertexindex].pos.x + 0.5f, vertices[vertexindex].pos.z + 0.5f); vertices[vertexindex].nml = Vec3(0.0f, -1.0f, 0.0f); indices[curr_index++] = vertexindex - 1; indices[curr_index++] = vertexindex - (slices + 1); indices[curr_index++] = vertexindex; } } } void Primitive::PrimitiveData::CalcTB(void) { //Calc T and B for each triangle, adding the results to the values for each vertex for (int i = 0; i < numIndices; i += 3) { int index0 = indices[i + 0]; int index1 = indices[i + 1]; int index2 = indices[i + 2]; float du1 = vertices[index1].tex.u - vertices[index0].tex.u; float du2 = vertices[index2].tex.u - vertices[index0].tex.u; float dv1 = vertices[index1].tex.v - vertices[index0].tex.v; float dv2 = vertices[index2].tex.v - vertices[index0].tex.v; Vec3 p = vertices[index1].pos - vertices[index0].pos; Vec3 q = vertices[index2].pos - vertices[index0].pos; Vec3 t = (p * dv2 - q * dv1) / (du1 * dv2 - dv1 * du2); Vec3 b = (p * du2 - q * du1) / (dv1 * du2 - du1 * dv2); vertices[index0].t += t; vertices[index0].b += b; ++vertices[index0].indices; vertices[index1].t += t; vertices[index1].b += b; ++vertices[index1].indices; vertices[index2].t += t; vertices[index2].b += b; ++vertices[index2].indices; } //Average the T and B values for each vertex for (int i = 0; i < numVertices; ++i) { float scale = 1.0f / vertices[i].indices; vertices[i].t *= scale; vertices[i].b *= scale; } }