Ready-to-use algorithms for the construction of box, cylinder, cone and sphere for OpenGL applications with preparation for texture and light effects.
Introduction
I want to write a simple X3DOM viewer, based on OpenGL, and searched the web for the construction of box, cylinder, cone and sphere. What I found were a lot of good forum posts, but nothing "ready-to-use". In this tip, I would like to share my findings with all those who are also looking for an introduction to exactly this topic. So please don't expect "rocket science" in the following, but just "ready-to-use" code.
There is another tip about "light source features and related material properties" that I also wrote in connection with the simple X3DOM viewer.
Background
The X3DOM specification supports the objects Box
, Cylinder
, Cone
and Sphere
, so I need an algorithm to construct these graphical primitives.
I am not yet very confident with OpenGL, so it is important to me that the algorithms are easy to understand and to follow. (One of my sources was the OpenGL Programming Guide.)
The results are geometrical primitives that support all types of OpenGL lighting (ambient, diffuse and specular) as well as texture. Unfortunately, the simultaneous use of all types of lighting and texture in OpenGL requires some tricks and extensions (EXT_secondary_color
), but that would be material for the next tip. What is already possible with on-board means is shown in the following pictures:
Geometric Promitives With Full Lighting
Geometric Promitives With Simple Texture
The triangle with the spectral colours marks the position of the light source in each case.
For cone and sphere, you can see well the approximation of the curved surface by plain surface sections. The quality of the approximation can be adjusted via the step size of the angle that is used for the plain surface sections - for the pictures, I use 60 steps per full circle/360°.
Using the Code
Box
Let's start with the box, straightforward code - no fancy tricks:
void OpenGL::DrawBox(float fWidthHalf, float fHeightHalf, float fDepthHalf, bool bTexture)
{
::glBegin(GL_TRIANGLES);
::glNormal3f(0.0f, 0.0f, +1.0f);
if (bTexture) ::glTexCoord2f(0.0f, 1.0f);
::glVertex3f(-fWidthHalf, +fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(0.0f, 0.0f);
::glVertex3f(-fWidthHalf, -fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 0.0f);
::glVertex3f(+fWidthHalf, -fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 0.0f);
::glVertex3f(+fWidthHalf, -fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 1.0f);
::glVertex3f(+fWidthHalf, +fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(0.0f, 1.0f);
::glVertex3f(-fWidthHalf, +fHeightHalf, +fDepthHalf);
::glEnd();
::glBegin(GL_TRIANGLES);
::glNormal3f(0.0f, 0.0f, -1.0f);
if (bTexture) ::glTexCoord2f(1.0f, 0.0f);
::glVertex3f(+fWidthHalf, -fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(0.0f, 0.0f);
::glVertex3f(-fWidthHalf, -fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(0.0f, 1.0f);
::glVertex3f(-fWidthHalf, +fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(0.0f, 1.0f);
::glVertex3f(-fWidthHalf, +fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 1.0f);
::glVertex3f(+fWidthHalf, +fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 0.0f);
::glVertex3f(+fWidthHalf, -fHeightHalf, -fDepthHalf);
::glEnd();
::glBegin(GL_TRIANGLES);
::glNormal3f(-1.0f, 0.0f, 0.0f);
if (bTexture) ::glTexCoord2f(0.0f, 1.0f);
::glVertex3f(-fWidthHalf, -fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 0.0f);
::glVertex3f(-fWidthHalf, +fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(0.0f, 0.0f);
::glVertex3f(-fWidthHalf, -fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(0.0f, 1.0f);
::glVertex3f(-fWidthHalf, -fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 1.0f);
::glVertex3f(-fWidthHalf, +fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 0.0f);
::glVertex3f(-fWidthHalf, +fHeightHalf, -fDepthHalf);
::glEnd();
::glBegin(GL_TRIANGLES);
::glNormal3f(+1.0f, 0.0f, 0.0f);
if (bTexture) ::glTexCoord2f(0.0f, 0.0f);
::glVertex3f(+fWidthHalf, -fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(0.0f, 1.0f);
::glVertex3f(+fWidthHalf, -fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 0.0f);
::glVertex3f(+fWidthHalf, +fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(0.0f, 1.0f);
::glVertex3f(+fWidthHalf, -fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 0.0f);
::glVertex3f(+fWidthHalf, +fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 1.0f);
::glVertex3f(+fWidthHalf, +fHeightHalf, +fDepthHalf);
::glEnd();
::glBegin(GL_TRIANGLES);
::glNormal3f(0.0f, +1.0f, 0.0f);
if (bTexture) ::glTexCoord2f(0.0f, 0.0f);
::glVertex3f(-fWidthHalf, +fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(0.0f, 1.0f);
::glVertex3f(-fWidthHalf, +fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 0.0f);
::glVertex3f(+fWidthHalf, +fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 0.0f);
::glVertex3f(+fWidthHalf, +fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(0.0f, 1.0f);
::glVertex3f(-fWidthHalf, +fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 1.0f);
::glVertex3f(+fWidthHalf, +fHeightHalf, +fDepthHalf);
::glEnd();
::glBegin(GL_TRIANGLES);
::glNormal3f(0.0f, -1.0f, 0.0f);
if (bTexture) ::glTexCoord2f(0.0f, 0.0f);
::glVertex3f(-fWidthHalf, -fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 0.0f);
::glVertex3f(+fWidthHalf, -fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(0.0f, 1.0f);
::glVertex3f(-fWidthHalf, -fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(0.0f, 1.0f);
::glVertex3f(-fWidthHalf, -fHeightHalf, +fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 0.0f);
::glVertex3f(+fWidthHalf, -fHeightHalf, -fDepthHalf);
if (bTexture) ::glTexCoord2f(1.0f, 1.0f);
::glVertex3f(+fWidthHalf, -fHeightHalf, +fDepthHalf);
::glEnd();
}
Cylinder
void OpenGL::DrawCylinder(float fWidthHalf, float fHeightHalf, float fDepthHalf,
double dAngleStep, const COLORREF* pColors = NULL, bool bTexture)
{
float fReciprocalPrecisition = (float)(dAngleStep / M_2PI);
if (pColors != NULL)
::glColor3f(MIN(1.0F, GetRValue(pColors[0]) / 255.0F),
MIN(1.0F, GetGValue(pColors[0]) / 255.0F),
MIN(1.0F, GetBValue(pColors[0]) / 255.0F));
int iSectorCount = 0;
::glBegin(GL_POLYGON);
for (double dTopAngle = M_2PI; dTopAngle > 0.0; dTopAngle -= dAngleStep)
{
::glNormal3f(0.0F, +1.0F, 0.0F);
double c = cos(dTopAngle);
double s = sin(dTopAngle);
float fTextureOffsetS = 0.5F + (float)(0.5F * c);
float fTextureOffsetT = 0.5F + (float)(0.5F * s);
if (bTexture) ::glTexCoord2f(fTextureOffsetS, fTextureOffsetT);
::glVertex3f((float)(fWidthHalf * cos(dTopAngle)),
fHeightHalf,
(float)(fDepthHalf * sin(dTopAngle)));
}
::glEnd();
if (pColors != NULL)
::glColor3f(MIN(1.0F, GetRValue(pColors[1]) / 255.0F),
MIN(1.0F, GetGValue(pColors[1]) / 255.0F),
MIN(1.0F, GetBValue(pColors[1]) / 255.0F));
iSectorCount = 0;
::glBegin(GL_TRIANGLES);
for (double dCoverAngle1 = 0; dCoverAngle1 < M_2PI; dCoverAngle1 += dAngleStep)
{
double dCoverAngle2 = dCoverAngle1 + dAngleStep;
float fWidthPart1 = (float)(fWidthHalf * cos(dCoverAngle1));
float fWidthPart2 = (float)(fWidthHalf * cos(dCoverAngle2));
float fDepthPart1 = (float)(fDepthHalf * sin(dCoverAngle1));
float fDepthPart2 = (float)(fDepthHalf * sin(dCoverAngle2));
::glNormal3f((float)(1.0F * cos(dCoverAngle1 + dAngleStep / 2)),
0.0F,
(float)(1.0F * sin(dCoverAngle1 + dAngleStep / 2)));
float fTextureOffsetS1 = (float)(iSectorCount ) * fReciprocalPrecisition;
float fTextureOffsetT1 = 0.0F;
float fTextureOffsetS2 = (float)(iSectorCount + 1) * fReciprocalPrecisition;
float fTextureOffsetT2 = 1.0F;
if (bTexture) ::glTexCoord2f(fTextureOffsetS1, fTextureOffsetT1);
::glVertex3f(fWidthPart1, -fHeightHalf, fDepthPart1);
if (bTexture) ::glTexCoord2f(fTextureOffsetS1, fTextureOffsetT2);
::glVertex3f(fWidthPart1, fHeightHalf, fDepthPart1);
if (bTexture) ::glTexCoord2f(fTextureOffsetS2, fTextureOffsetT2);
::glVertex3f(fWidthPart2, fHeightHalf, fDepthPart2);
if (bTexture) ::glTexCoord2f(fTextureOffsetS2, fTextureOffsetT2);
::glVertex3f(fWidthPart2, fHeightHalf, fDepthPart2);
if (bTexture) ::glTexCoord2f(fTextureOffsetS2, fTextureOffsetT1);
::glVertex3f(fWidthPart2, -fHeightHalf, fDepthPart2);
if (bTexture) ::glTexCoord2f(fTextureOffsetS1, fTextureOffsetT1);
::glVertex3f(fWidthPart1, -fHeightHalf, fDepthPart1);
iSectorCount++;
}
::glEnd();
if (pColors != NULL)
::glColor3f(MIN(1.0F, GetRValue(pColors[2]) / 255.0F),
MIN(1.0F, GetGValue(pColors[2]) / 255.0F),
MIN(1.0F, GetBValue(pColors[2]) / 255.0F));
iSectorCount = 0;
::glBegin(GL_POLYGON);
for (double dBottotmAngle = 0; dBottotmAngle < M_2PI; dBottotmAngle += dAngleStep)
{
::glNormal3f(0.0F, -1.0F, 0.0F);
double c = cos(dBottotmAngle);
double s = sin(dBottotmAngle);
float fTextureOffsetS = 0.5F + (float)(0.5F * c);
float fTextureOffsetT = 0.5F + (float)(0.5F * s);
if (bTexture) ::glTexCoord2f(fTextureOffsetS, fTextureOffsetT);
::glVertex3f((float)(fWidthHalf * cos(dBottotmAngle)),
-fHeightHalf,
(float)(fDepthHalf * sin(dBottotmAngle)));
}
::glEnd();
}
Cone
approximate a curved surface.</param>
void DrawCone(float fWidthHalf, float fHeightHalf, float fDepthHalf,
double dAngleStep, const COLORREF* pColors = NULL, bool bTexture = false);
{
float fReciprocalPrecisition = (float)(dAngleStep / M_2PI);
if (pColors != NULL)
::glColor3f(MIN(1.0F, GetRValue(pColors[0]) / 255.0F),
MIN(1.0F, GetGValue(pColors[0]) / 255.0F),
MIN(1.0F, GetBValue(pColors[0]) / 255.0F));
int iSectorCount = 0;
::glBegin(GL_TRIANGLES);
for (double dCoverAngle1 = 0.0F; dCoverAngle1 < M_2PI; dCoverAngle1 += dAngleStep)
{
double dCoverAngle2 = dCoverAngle1 + dAngleStep;
float fWidthPart1 = (float)(fWidthHalf * cos(dCoverAngle1));
float fWidthPart2 = (float)(fWidthHalf * cos(dCoverAngle2));
float fDepthPart1 = (float)(fDepthHalf * sin(dCoverAngle1));
float fDepthPart2 = (float)(fDepthHalf * sin(dCoverAngle2));
::glNormal3f((fWidthPart1 + fWidthPart2) / 2, 0.0F, (fDepthPart1 + fDepthPart2) / 2);
float fTextureOffsetS1 = iSectorCount * fReciprocalPrecisition;
float fTextureOffsetS2 = (iSectorCount + 1) * fReciprocalPrecisition;
if (bTexture) ::glTexCoord2f(fTextureOffsetS1, 1.0);
::glVertex3f(0.0F, fHeightHalf, 0.0F);
if (bTexture) ::glTexCoord2f(fTextureOffsetS2, 0.0);
::glVertex3f(fWidthPart2, -fHeightHalf, fDepthPart2);
if (bTexture) ::glTexCoord2f(fTextureOffsetS2, 0.0);
::glVertex3f(fWidthPart1, -fHeightHalf, fDepthPart1);
iSectorCount++;
}
::glEnd();
if (pColors != NULL)
::glColor3f(MIN(1.0F, GetRValue(pColors[1]) / 255.0F),
MIN(1.0F, GetGValue(pColors[1]) / 255.0F),
MIN(1.0F, GetBValue(pColors[1]) / 255.0F));
iSectorCount = 0;
::glBegin(GL_POLYGON); for (double dBottomAngle = 0; dBottomAngle < M_2PI; dBottomAngle += dAngleStep)
{
::glNormal3f(0.0F, -1.0F, 0.0F);
double c = cos(dBottomAngle);
double s = sin(dBottomAngle);
float fTextureOffsetS = 0.5F + (float)(0.5F * c);
float fTextureOffsetT = 0.5F + (float)(0.5F * s);
if (bTexture) ::glTexCoord2f(fTextureOffsetS, fTextureOffsetT);
::glVertex3f((float)(fWidthHalf * c), -fHeightHalf, (float)(fDepthHalf * s));
}
::glEnd();
}
Sphere
approximate a curved surface.</param>
void DrawSphere(float fWidthHalf, float fHeightHalf, float fDepthHalf,
double dAngleStep, bool bTexture = false)
{
float f1_10thPi = (float)(M_PI * 0.1f);
float f2_10thPi = (float)(M_PI * 0.2f);
float f3_10thPi = (float)(M_PI * 0.3f);
float f7_10thPi = (float)(M_PI * 0.7f);
float f8_10thPi = (float)(M_PI * 0.8f);
float f9_10thPi = (float)(M_PI * 0.9f);
float fPiQuarter = (float)(M_PI * 0.25f);
float fPiHalf = (float)(M_PI * 0.50f);
float fReciprocalPrecisition = dAngleStep / M_2PI;
int iStackCount = 0;
::glBegin(GL_TRIANGLES);
for (double dStackAngle1 = 0.0f; dStackAngle1 < M_PI; dStackAngle1 += dAngleStep)
{
double dStackAngle2 = dStackAngle1 + dAngleStep;
double s1 = sin(dStackAngle1);
double s2 = sin(dStackAngle2);
float fStackHeightHalf1 = (float)(-fHeightHalf * cos(dStackAngle1));
float fStackHeightHalf2 = (float)(-fHeightHalf * cos(dStackAngle2));
float fStackWidthHalfTop = (float)(fWidthHalf * s1);
float fStackWidthHalfBtm = (float)(fWidthHalf * s2);
float fStackDepthHalfTop = (float)(fDepthHalf * s1);
float fStackDepthHalfBtm = (float)(fDepthHalf * s2);
int iSectorCount = 0;
for (double dSectorAngle1 = 0.0f; dSectorAngle1 < M_2PI; dSectorAngle1 += dAngleStep)
{
double dSectorAngle2 = dSectorAngle1 + dAngleStep;
float fLeftTop[3] = { (float)(fStackWidthHalfTop * cos(dSectorAngle1)),
fStackHeightHalf1,
(float)(fStackDepthHalfTop * sin(dSectorAngle1)) };
float fRghtTop[3] = { (float)(fStackWidthHalfTop * cos(dSectorAngle2)),
fStackHeightHalf1,
(float)(fStackDepthHalfTop * sin(dSectorAngle2)) };
float fLeftBtm[3] = { (float)(fStackWidthHalfBtm * cos(dSectorAngle1)),
fStackHeightHalf2,
(float)(fStackDepthHalfBtm * sin(dSectorAngle1)) };
float fRghtBtm[3] = { (float)(fStackWidthHalfBtm * cos(dSectorAngle2)),
fStackHeightHalf2,
(float)(fStackDepthHalfBtm * sin(dSectorAngle2)) };
float n[3] = { (fLeftTop[0] + fRghtBtm[0]) / 2,
(fStackHeightHalf1 + fStackHeightHalf2) / 2,
(fLeftTop[2] + fRghtBtm[2]) / 2 };
float fTextureOffsetS1 = iSectorCount * fReciprocalPrecisition;
float fTextureOffsetT1 = 2 * iStackCount * fReciprocalPrecisition;
float fTextureOffsetS2 = (iSectorCount + 1) * fReciprocalPrecisition;
float fTextureOffsetT2 = 2 * (iStackCount + 1) * fReciprocalPrecisition;
if (fLeftBtm[0] != fRghtBtm[0] || fLeftBtm[2] != fRghtBtm[2])
{
::glNormal3f(n[0], n[1], n[2]);
if (bTexture) ::glTexCoord2f(fTextureOffsetS1, fTextureOffsetT1);
::glVertex3fv(fLeftTop);
if (bTexture) ::glTexCoord2f(fTextureOffsetS1, fTextureOffsetT2);
::glVertex3fv(fLeftBtm);
if (bTexture) ::glTexCoord2f(fTextureOffsetS2, fTextureOffsetT2);
::glVertex3fv(fRghtBtm);
}
if (fLeftTop[0] != fRghtTop[0] || fLeftTop[2] != fRghtTop[2])
{
::glNormal3f(n[0], n[1], n[2]);
if (bTexture) ::glTexCoord2f(fTextureOffsetS1, fTextureOffsetT1);
::glVertex3fv(fLeftTop);
if (bTexture) ::glTexCoord2f(fTextureOffsetS2, fTextureOffsetT2);
::glVertex3fv(fRghtBtm);
if (bTexture) ::glTexCoord2f(fTextureOffsetS2, fTextureOffsetT1);
::glVertex3fv(fRghtTop);
}
iSectorCount++;
}
iStackCount++;
}
::glEnd();
}
Environment
The calling environment for Box
, Cylinder
, Cone
and Sphere
are like two peas in a pod - that's why I only present the calling environment of Box
here:
void Box::RenderToOpenGL(X3DNode* pParentNode, HDC dcOpenGlWindow)
{
Vector3f size = GetSize();
GLuint uiTextureID = 0;
X3DShapeNode* pParentShape = dynamic_cast<X3DShapeNode*>(pParentNode);
if (pParentShape != NULL)
{
X3DAppearanceNode* pAppearence = pParentShape->GetAppearance();
if ((Appearance*)pAppearence != NULL)
{
((Appearance*)pAppearence)->ApplyMaterial(dcOpenGlWindow);
uiTextureID = ((Appearance*)pAppearence)->ApplyTexture(dcOpenGlWindow);
}
}
if (uiTextureID != 0)
{
::glBindTexture(GL_TEXTURE_2D, uiTextureID);
::glEnable(GL_TEXTURE_2D);
}
OpenGL::DrawBox(size.x * 0.5f, size.y * 0.5f, size.z * 0.5f, (uiTextureID != 0));
if (uiTextureID != 0)
{
::glDisable(GL_TEXTURE_2D);
::glBindTexture(GL_TEXTURE_2D, 0);
}
}
Since my application is to be an X3DOM viewer, I also use the class hierarchy of X3DOM. According to this, Material
and Texture
(grouped by Appearance
) together with the Box
/Cylinder
/Cone
/Sphere
are children of a Shape
.
Material and Texture
The following code is behind ApplyMaterial(...)
and ApplyTexture(...)
(currently only a very small part of the X3DOM specification is implemented):
void Appearance::ApplyMaterial(HDC dcOpenGlWindow)
{
X3DMaterialNode* pMaterial = GetMaterial();
if (pMaterial != NULL)
{
SFColor oColor = pMaterial->GetDiffuseColor();
::glColor3f(oColor.r, oColor.g, oColor.b);
}
else
{
SFColor oColor = CSSColors::Colors[CSSColors::IndexOf(L"Gray")].Value;
::glColor3f(oColor.r, oColor.g, oColor.b);
}
}
GLuint Appearance::ApplyTexture(HDC dcOpenGlWindow)
{
GLuint uiTextureID = 0;
X3DTextureNode* pTexture = GetTexture();
if (pTexture != NULL)
{
String strUri = pTexture->GetUri();
if (!String::IsNullOrEmpty(strUri))
{
uiTextureID = OpenGL::GetTexture(strUri.Value());
if (uiTextureID == 0)
{
uiTextureID = OpenGL::AddTexture(strUri.Value(), dcOpenGlWindow);
}
}
}
return uiTextureID;
}
Just for the sake of completeness, here is the code of AddTexture(...)
(currently only 24bpp bitmaps are supported, as they can be created with MS Paint, for example):
GLuint OpenGL::AddTexture(const WCHAR* wszFilename, HDC dcOpenGlWindow)
{
GLuint uiTextureID = 0;
::glGenTextures(1, &uiTextureID);
if (uiTextureID == 0)
{
Console::WriteError(
L"OpenGL::AddTexture() Failed to acquire a new texture (name/id)!\n");
return uiTextureID;
}
int iWidth = 0;
int iHeight = 0;
BYTE* pbyBitmapPixel = NULL;
if (OpenGL::LoadTextureImageFile(wszFilename, dcOpenGlWindow, iWidth, iHeight,
&pbyBitmapPixel))
{
::glEnable(GL_TEXTURE_2D);
::glBindTexture(GL_TEXTURE_2D, uiTextureID);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
::glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
::glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
::glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, iWidth, iHeight, 0,
GL_BGR_EXT, GL_UNSIGNED_BYTE, pbyBitmapPixel);
__GLEXTFP_GLGENERATEMIPMAPS __glextGenerateMipmaps =
(__GLEXTFP_GLGENERATEMIPMAPS)__GLEXT_GetProcAddress("glGenerateMipmaps");
if (__glextGenerateMipmaps != NULL)
__glextGenerateMipmaps(GL_TEXTURE_2D);
else
Console::WriteWarning(
L" OpenGL::AddTexture() Extension 'glGenerateMipmaps' not available!\n");
free(pbyBitmapPixel);
pbyBitmapPixel = NULL;
::glBindTexture(GL_TEXTURE_2D, 0);
::glDisable(GL_TEXTURE_2D);
_textures[wszFilename] = uiTextureID;
}
else
{
Console::WriteError(
L"OpenGL::AddTexture() Failed to assign bitmap to new texture (name/id)!\n");
::glDeleteTextures(1, &uiTextureID);
uiTextureID = 0;
}
return uiTextureID;
}
That's it. Have fun with OpenGL!
Points of Interest
Even though the mathematics behind the ::glBegin(GL_TRIANGLES)
and ::glEnd()
is clear - setting all coordinates correctly took a bit of trial & error. The same applies to ::glNormal3f(...)
and ::glTexCoord2f(...)
.
History
- 10th March, 2021: Initial tip
- 17th April, 2021: Added the pColors argument to cylinder and cone