// Draw a cylinder. Much like gluCylinder void gltMakeCylinder(GLTriangleBatch& cylinderBatch, GLfloat baseRadius, GLfloat topRadius, GLfloat fLength, GLint numSlices, GLint numStacks) { float fRadiusStep = (topRadius - baseRadius) / float(numStacks); GLfloat fStepSizeSlice = (3.1415926536f * 2.0f) / float(numSlices); M3DVector3f vVertex[4]; M3DVector3f vNormal[4]; M3DVector2f vTexture[4]; cylinderBatch.BeginMesh(numSlices * numStacks * 6); GLfloat ds = 1.0f / float(numSlices); GLfloat dt = 1.0f / float(numStacks); GLfloat s; GLfloat t; for (int i = 0; i < numStacks; i++) { if(i == 0) t = 0.0f; else t = float(i) * dt; float tNext; if(i == (numStacks - 1)) tNext = 1.0f; else tNext = float(i+1) * dt; float fCurrentRadius = baseRadius + (fRadiusStep * float(i)); float fNextRadius = baseRadius + (fRadiusStep * float(i+1)); float theyta; float theytaNext; float fCurrentZ = float(i) * (fLength / float(numStacks)); float fNextZ = float(i+1) * (fLength / float(numStacks)); float zNormal = 0.0f; if(!m3dCloseEnough(baseRadius - topRadius, 0.0f, 0.00001f)) { // Rise over run... zNormal = (baseRadius - topRadius); } for (int j = 0; j < numSlices; j++) { if(j == 0) s = 0.0f; else s = float(j) * ds; float sNext; if(j == (numSlices -1)) sNext = 1.0f; else sNext = float(j+1) * ds; theyta = fStepSizeSlice * float(j); if(j == (numSlices - 1)) theytaNext = 0.0f; else theytaNext = fStepSizeSlice * (float(j+1)); // Inner First vVertex[1][0] = cos(theyta) * fCurrentRadius; // X vVertex[1][1] = sin(theyta) * fCurrentRadius; // Y vVertex[1][2] = fCurrentZ; // Z vNormal[1][0] = vVertex[1][0]; // Surface Normal, same for everybody vNormal[1][1] = vVertex[1][1]; vNormal[1][2] = zNormal; m3dNormalizeVector3(vNormal[1]); vTexture[1][0] = s; // Texture Coordinates, I have no idea... vTexture[1][1] = t; // Outer First vVertex[0][0] = cos(theyta) * fNextRadius; // X vVertex[0][1] = sin(theyta) * fNextRadius; // Y vVertex[0][2] = fNextZ; // Z if(!m3dCloseEnough(fNextRadius, 0.0f, 0.00001f)) { vNormal[0][0] = vVertex[0][0]; // Surface Normal, same for everybody vNormal[0][1] = vVertex[0][1]; // For cones, tip is tricky vNormal[0][2] = zNormal; m3dNormalizeVector3(vNormal[0]); } else memcpy(vNormal[0], vNormal[1], sizeof(M3DVector3f)); vTexture[0][0] = s; // Texture Coordinates, I have no idea... vTexture[0][1] = tNext; // Inner second vVertex[3][0] = cos(theytaNext) * fCurrentRadius; // X vVertex[3][1] = sin(theytaNext) * fCurrentRadius; // Y vVertex[3][2] = fCurrentZ; // Z vNormal[3][0] = vVertex[3][0]; // Surface Normal, same for everybody vNormal[3][1] = vVertex[3][1]; vNormal[3][2] = zNormal; m3dNormalizeVector3(vNormal[3]); vTexture[3][0] = sNext; // Texture Coordinates, I have no idea... vTexture[3][1] = t; // Outer second vVertex[2][0] = cos(theytaNext) * fNextRadius; // X vVertex[2][1] = sin(theytaNext) * fNextRadius; // Y vVertex[2][2] = fNextZ; // Z if(!m3dCloseEnough(fNextRadius, 0.0f, 0.00001f)) { vNormal[2][0] = vVertex[2][0]; // Surface Normal, same for everybody vNormal[2][1] = vVertex[2][1]; vNormal[2][2] = zNormal; m3dNormalizeVector3(vNormal[2]); } else memcpy(vNormal[2], vNormal[3], sizeof(M3DVector3f)); vTexture[2][0] = sNext; // Texture Coordinates, I have no idea... vTexture[2][1] = tNext; cylinderBatch.AddTriangle(vVertex, vNormal, vTexture); // Rearrange for next triangle memcpy(vVertex[0], vVertex[1], sizeof(M3DVector3f)); memcpy(vNormal[0], vNormal[1], sizeof(M3DVector3f)); memcpy(vTexture[0], vTexture[1], sizeof(M3DVector2f)); memcpy(vVertex[1], vVertex[3], sizeof(M3DVector3f)); memcpy(vNormal[1], vNormal[3], sizeof(M3DVector3f)); memcpy(vTexture[1], vTexture[3], sizeof(M3DVector2f)); cylinderBatch.AddTriangle(vVertex, vNormal, vTexture); } } cylinderBatch.End(); }
///////////////////////////////////////////////////////////////////////////////////////////////// // Make a sphere void gltMakeSphere(GLTriangleBatch& sphereBatch, GLfloat fRadius, GLint iSlices, GLint iStacks) { GLfloat drho = (GLfloat)(3.141592653589) / (GLfloat) iStacks; GLfloat dtheta = 2.0f * (GLfloat)(3.141592653589) / (GLfloat) iSlices; GLfloat ds = 1.0f / (GLfloat) iSlices; GLfloat dt = 1.0f / (GLfloat) iStacks; GLfloat t = 1.0f; GLfloat s = 0.0f; GLint i, j; // Looping variables sphereBatch.BeginMesh(iSlices * iStacks * 6); for (i = 0; i < iStacks; i++) { GLfloat rho = (GLfloat)i * drho; GLfloat srho = (GLfloat)(sin(rho)); GLfloat crho = (GLfloat)(cos(rho)); GLfloat srhodrho = (GLfloat)(sin(rho + drho)); GLfloat crhodrho = (GLfloat)(cos(rho + drho)); // Many sources of OpenGL sphere drawing code uses a triangle fan // for the caps of the sphere. This however introduces texturing // artifacts at the poles on some OpenGL implementations s = 0.0f; M3DVector3f vVertex[4]; M3DVector3f vNormal[4]; M3DVector2f vTexture[4]; for ( j = 0; j < iSlices; j++) { GLfloat theta = (j == iSlices) ? 0.0f : j * dtheta; GLfloat stheta = (GLfloat)(-sin(theta)); GLfloat ctheta = (GLfloat)(cos(theta)); GLfloat x = stheta * srho; GLfloat y = ctheta * srho; GLfloat z = crho; vTexture[0][0] = s; vTexture[0][1] = t; vNormal[0][0] = x; vNormal[0][1] = y; vNormal[0][2] = z; vVertex[0][0] = x * fRadius; vVertex[0][1] = y * fRadius; vVertex[0][2] = z * fRadius; x = stheta * srhodrho; y = ctheta * srhodrho; z = crhodrho; vTexture[1][0] = s; vTexture[1][1] = t - dt; vNormal[1][0] = x; vNormal[1][1] = y; vNormal[1][2] = z; vVertex[1][0] = x * fRadius; vVertex[1][1] = y * fRadius; vVertex[1][2] = z * fRadius; theta = ((j+1) == iSlices) ? 0.0f : (j+1) * dtheta; stheta = (GLfloat)(-sin(theta)); ctheta = (GLfloat)(cos(theta)); x = stheta * srho; y = ctheta * srho; z = crho; s += ds; vTexture[2][0] = s; vTexture[2][1] = t; vNormal[2][0] = x; vNormal[2][1] = y; vNormal[2][2] = z; vVertex[2][0] = x * fRadius; vVertex[2][1] = y * fRadius; vVertex[2][2] = z * fRadius; x = stheta * srhodrho; y = ctheta * srhodrho; z = crhodrho; vTexture[3][0] = s; vTexture[3][1] = t - dt; vNormal[3][0] = x; vNormal[3][1] = y; vNormal[3][2] = z; vVertex[3][0] = x * fRadius; vVertex[3][1] = y * fRadius; vVertex[3][2] = z * fRadius; sphereBatch.AddTriangle(vVertex, vNormal, vTexture); // Rearrange for next triangle memcpy(vVertex[0], vVertex[1], sizeof(M3DVector3f)); memcpy(vNormal[0], vNormal[1], sizeof(M3DVector3f)); memcpy(vTexture[0], vTexture[1], sizeof(M3DVector2f)); memcpy(vVertex[1], vVertex[3], sizeof(M3DVector3f)); memcpy(vNormal[1], vNormal[3], sizeof(M3DVector3f)); memcpy(vTexture[1], vTexture[3], sizeof(M3DVector2f)); sphereBatch.AddTriangle(vVertex, vNormal, vTexture); } t -= dt; } sphereBatch.End(); }
void gltMakeDisk(GLTriangleBatch& diskBatch, GLfloat innerRadius, GLfloat outerRadius, GLint nSlices, GLint nStacks) { // How much to step out each stack GLfloat fStepSizeRadial = outerRadius - innerRadius; if(fStepSizeRadial < 0.0f) // Dum dum... fStepSizeRadial *= -1.0f; fStepSizeRadial /= float(nStacks); GLfloat fStepSizeSlice = (3.1415926536f * 2.0f) / float(nSlices); diskBatch.BeginMesh(nSlices * nStacks * 6); M3DVector3f vVertex[4]; M3DVector3f vNormal[4]; M3DVector2f vTexture[4]; float fRadialScale = 1.0f / outerRadius; for(GLint i = 0; i < nStacks; i++) // Stacks { float theyta; float theytaNext; for(GLint j = 0; j < nSlices; j++) // Slices { float inner = innerRadius + (float(i)) * fStepSizeRadial; float outer = innerRadius + (float(i+1)) * fStepSizeRadial; theyta = fStepSizeSlice * float(j); if(j == (nSlices - 1)) theytaNext = 0.0f; else theytaNext = fStepSizeSlice * (float(j+1)); // Inner First vVertex[0][0] = cos(theyta) * inner; // X vVertex[0][1] = sin(theyta) * inner; // Y vVertex[0][2] = 0.0f; // Z vNormal[0][0] = 0.0f; // Surface Normal, same for everybody vNormal[0][1] = 0.0f; vNormal[0][2] = 1.0f; vTexture[0][0] = ((vVertex[0][0] * fRadialScale) + 1.0f) * 0.5f; vTexture[0][1] = ((vVertex[0][1] * fRadialScale) + 1.0f) * 0.5f; // Outer First vVertex[1][0] = cos(theyta) * outer; // X vVertex[1][1] = sin(theyta) * outer; // Y vVertex[1][2] = 0.0f; // Z vNormal[1][0] = 0.0f; // Surface Normal, same for everybody vNormal[1][1] = 0.0f; vNormal[1][2] = 1.0f; vTexture[1][0] = ((vVertex[1][0] * fRadialScale) + 1.0f) * 0.5f; vTexture[1][1] = ((vVertex[1][1] * fRadialScale) + 1.0f) * 0.5f; // Inner Second vVertex[2][0] = cos(theytaNext) * inner; // X vVertex[2][1] = sin(theytaNext) * inner; // Y vVertex[2][2] = 0.0f; // Z vNormal[2][0] = 0.0f; // Surface Normal, same for everybody vNormal[2][1] = 0.0f; vNormal[2][2] = 1.0f; vTexture[2][0] = ((vVertex[2][0] * fRadialScale) + 1.0f) * 0.5f; vTexture[2][1] = ((vVertex[2][1] * fRadialScale) + 1.0f) * 0.5f; // Outer Second vVertex[3][0] = cos(theytaNext) * outer; // X vVertex[3][1] = sin(theytaNext) * outer; // Y vVertex[3][2] = 0.0f; // Z vNormal[3][0] = 0.0f; // Surface Normal, same for everybody vNormal[3][1] = 0.0f; vNormal[3][2] = 1.0f; vTexture[3][0] = ((vVertex[3][0] * fRadialScale) + 1.0f) * 0.5f; vTexture[3][1] = ((vVertex[3][1] * fRadialScale) + 1.0f) * 0.5f; diskBatch.AddTriangle(vVertex, vNormal, vTexture); // Rearrange for next triangle memcpy(vVertex[0], vVertex[1], sizeof(M3DVector3f)); memcpy(vNormal[0], vNormal[1], sizeof(M3DVector3f)); memcpy(vTexture[0], vTexture[1], sizeof(M3DVector2f)); memcpy(vVertex[1], vVertex[3], sizeof(M3DVector3f)); memcpy(vNormal[1], vNormal[3], sizeof(M3DVector3f)); memcpy(vTexture[1], vTexture[3], sizeof(M3DVector2f)); diskBatch.AddTriangle(vVertex, vNormal, vTexture); } } diskBatch.End(); }
// Draw a torus (doughnut) at z = fZVal... torus is in xy plane void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor) { double majorStep = 2.0f*M3D_PI / numMajor; double minorStep = 2.0f*M3D_PI / numMinor; int i, j; torusBatch.BeginMesh(numMajor * (numMinor+1) * 6); for (i=0; i<numMajor; ++i) { double a0 = i * majorStep; double a1 = a0 + majorStep; GLfloat x0 = (GLfloat) cos(a0); GLfloat y0 = (GLfloat) sin(a0); GLfloat x1 = (GLfloat) cos(a1); GLfloat y1 = (GLfloat) sin(a1); M3DVector3f vVertex[4]; M3DVector3f vNormal[4]; M3DVector2f vTexture[4]; for (j=0; j<=numMinor; ++j) { double b = j * minorStep; GLfloat c = (GLfloat) cos(b); GLfloat r = minorRadius * c + majorRadius; GLfloat z = minorRadius * (GLfloat) sin(b); // First point vTexture[0][0] = (float)(i)/(float)(numMajor); vTexture[0][1] = (float)(j)/(float)(numMinor); vNormal[0][0] = x0*c; vNormal[0][1] = y0*c; vNormal[0][2] = z/minorRadius; m3dNormalizeVector3(vNormal[0]); vVertex[0][0] = x0 * r; vVertex[0][1] = y0 * r; vVertex[0][2] = z; // Second point vTexture[1][0] = (float)(i+1)/(float)(numMajor); vTexture[1][1] = (float)(j)/(float)(numMinor); vNormal[1][0] = x1*c; vNormal[1][1] = y1*c; vNormal[1][2] = z/minorRadius; m3dNormalizeVector3(vNormal[1]); vVertex[1][0] = x1*r; vVertex[1][1] = y1*r; vVertex[1][2] = z; // Next one over b = (j+1) * minorStep; c = (GLfloat) cos(b); r = minorRadius * c + majorRadius; z = minorRadius * (GLfloat) sin(b); // Third (based on first) vTexture[2][0] = (float)(i)/(float)(numMajor); vTexture[2][1] = (float)(j+1)/(float)(numMinor); vNormal[2][0] = x0*c; vNormal[2][1] = y0*c; vNormal[2][2] = z/minorRadius; m3dNormalizeVector3(vNormal[2]); vVertex[2][0] = x0 * r; vVertex[2][1] = y0 * r; vVertex[2][2] = z; // Fourth (based on second) vTexture[3][0] = (float)(i+1)/(float)(numMajor); vTexture[3][1] = (float)(j+1)/(float)(numMinor); vNormal[3][0] = x1*c; vNormal[3][1] = y1*c; vNormal[3][2] = z/minorRadius; m3dNormalizeVector3(vNormal[3]); vVertex[3][0] = x1*r; vVertex[3][1] = y1*r; vVertex[3][2] = z; torusBatch.AddTriangle(vVertex, vNormal, vTexture); // Rearrange for next triangle memcpy(vVertex[0], vVertex[1], sizeof(M3DVector3f)); memcpy(vNormal[0], vNormal[1], sizeof(M3DVector3f)); memcpy(vTexture[0], vTexture[1], sizeof(M3DVector2f)); memcpy(vVertex[1], vVertex[3], sizeof(M3DVector3f)); memcpy(vNormal[1], vNormal[3], sizeof(M3DVector3f)); memcpy(vTexture[1], vTexture[3], sizeof(M3DVector2f)); torusBatch.AddTriangle(vVertex, vNormal, vTexture); } } torusBatch.End(); }