Commits

Jason McKesson committed 6fe4304

Tut14: Material texture works.
Also added glimg library.

  • Participants
  • Parent commits 05113d8

Comments (0)

Files changed (62)

Tut 14 Textures Are Not Pictures/Material Texture.cpp

 #include <string>
 #include <vector>
 #include <stack>
+#include <memory>
 #include <math.h>
 #include <stdio.h>
 #include <glload/gl_3_3.h>
+#include <glimg/glimg.h>
+#include <glimg/ImageCreatorExceptions.h>
 #include <GL/freeglut.h>
 #include "../framework/framework.h"
 #include "../framework/Mesh.h"
 float g_fzNear = 1.0f;
 float g_fzFar = 1000.0f;
 
-ProgramData g_litShaderProg;
+ProgramData g_litFixedProg;
 ProgramData g_litTextureProg;
 
 UnlitProgData g_Unlit;
 const int g_projectionBlockIndex = 2;
 
 const int g_gaussTexUnit = 0;
+const int g_shineTexUnit = 1;
 
 UnlitProgData LoadUnlitProgram(const std::string &strVertexShader, const std::string &strFragmentShader)
 {
 	glUniformBlockBinding(data.theProgram, projectionBlock, g_projectionBlockIndex);
 
 	GLuint gaussianTextureUnif = glGetUniformLocation(data.theProgram, "gaussianTexture");
+	GLuint shininessTextureUnif = glGetUniformLocation(data.theProgram, "shininessTexture");
 	glUseProgram(data.theProgram);
 	glUniform1i(gaussianTextureUnif, g_gaussTexUnit);
+	glUniform1i(shininessTextureUnif, g_shineTexUnit);
 	glUseProgram(0);
 
 	return data;
 
 void InitializePrograms()
 {
-	g_litShaderProg = LoadLitMeshProgram("PN.vert", "ShaderGaussian.frag");
-	g_litTextureProg = LoadLitMeshProgram("PN.vert", "TextureGaussian.frag");
+	g_litFixedProg = LoadLitMeshProgram("PN.vert", "FixedShininess.frag");
+	g_litTextureProg = LoadLitMeshProgram("PNT.vert", "TextureShininess.frag");
 
 	g_Unlit = LoadUnlitProgram("Unlit.vert", "Unlit.frag");
 }
 
-Framework::RadiusDef radiusDef = {10.0f, 3.0f, 70.0f, 3.5f, 1.5f};
+Framework::RadiusDef radiusDef = {10.0f, 3.0f, 70.0f, 1.5f, 0.5f};
 glm::vec3 objectCenter = glm::vec3(0.0f, 0.0f, 0.0f);
 
 Framework::MousePole g_mousePole(objectCenter, radiusDef);
 	glSamplerParameteri(g_gaussSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 }
 
+GLuint g_shineTexture = 0;
+
+void CreateShininessTexture()
+{
+	std::auto_ptr<glimg::ImageSet> pImageSet;
+
+	try
+	{
+		pImageSet.reset(glimg::loaders::stb::LoadFromFile("data\\main.tga"));
+		std::auto_ptr<glimg::Image> pImage(pImageSet->GetImage(0, 0, 0));
+
+		glimg::Dimensions dims = pImage->GetDimensions();
+
+		glGenTextures(1, &g_shineTexture);
+		glBindTexture(GL_TEXTURE_2D, g_shineTexture);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, dims.width, dims.height, 0,
+			GL_RGB, GL_UNSIGNED_BYTE, pImage->GetImageData());
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+		glBindTexture(GL_TEXTURE_2D, 0);
+	}
+	catch(glimg::ImageCreationException &e)
+	{
+		printf(e.what());
+		throw;
+	}
+}
+
 
 //Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
 void init()
 	glBindBuffer(GL_UNIFORM_BUFFER, 0);
 
 	CreateGaussianTextures();
+	CreateShininessTexture();
 }
 
 bool g_bDrawCameraPos = false;
 			glm::mat3 normMatrix(modelMatrix.Top());
 			normMatrix = glm::transpose(glm::inverse(normMatrix));
 
-			ProgramData &prog = g_bUseTexture ? g_litTextureProg : g_litShaderProg;
+			ProgramData &prog = g_bUseTexture ? g_litTextureProg : g_litFixedProg;
 
 			glUseProgram(prog.theProgram);
 			glUniformMatrix4fv(prog.modelToCameraMatrixUnif, 1, GL_FALSE,
 			glBindTexture(GL_TEXTURE_2D, g_gaussTextures[g_currTexture]);
 			glBindSampler(g_gaussTexUnit, g_gaussSampler);
 
-			g_pObjectMesh->Render("lit");
+			glActiveTexture(GL_TEXTURE0 + g_shineTexUnit);
+			glBindTexture(GL_TEXTURE_2D, g_shineTexture);
+			glBindSampler(g_shineTexUnit, g_gaussSampler);
+
+			if(g_bUseTexture)
+				g_pObjectMesh->Render("lit-tex");
+			else
+				g_pObjectMesh->Render("lit");
 
 			glBindSampler(g_gaussTexUnit, 0);
 			glBindTexture(GL_TEXTURE_2D, 0);
 	case 32:
 		g_bUseTexture = !g_bUseTexture;
 		if(g_bUseTexture)
-			printf("Texture\n");
+			printf("Texture Shininess\n");
 		else
-			printf("Shader\n");
+			printf("Fixed Shininess\n");
 		break;
 	}
 

Tut 14 Textures Are Not Pictures/data/TextureShininess.frag

 
 in vec3 vertexNormal;
 in vec3 cameraSpacePosition;
+in vec2 shinTexCoord;
 
 out vec4 outputColor;
 
 } Lgt;
 
 uniform sampler2D gaussianTexture;
-uniform sampler2D 
+uniform sampler2D shininessTexture;
 
 float CalcAttenuation(in vec3 cameraSpacePosition,
 	in vec3 cameraSpaceLightPos,
 }
 
 vec4 ComputeLighting(in PerLight lightData, in vec3 cameraSpacePosition,
-	in vec3 cameraSpaceNormal)
+	in vec3 cameraSpaceNormal, in float specularShininess)
 {
 	vec3 lightDir;
 	vec4 lightIntensity;
 	vec3 halfAngle = normalize(lightDir + viewDirection);
 	vec2 texCoord;
 	texCoord.s = dot(halfAngle, surfaceNormal);
-	texCoord.t = Mtl.specularShininess;
+	texCoord.t = specularShininess;
 	float gaussianTerm = texture(gaussianTexture, texCoord).r;
 
 	gaussianTerm = cosAngIncidence != 0.0 ? gaussianTerm : 0.0;
 
 void main()
 {
+	float specularShininess = texture(shininessTexture, shinTexCoord).r;
+
 	vec4 accumLighting = Mtl.diffuseColor * Lgt.ambientIntensity;
 	for(int light = 0; light < numberOfLights; light++)
 	{
 		accumLighting += ComputeLighting(Lgt.lights[light],
-			cameraSpacePosition, vertexNormal);
+			cameraSpacePosition, vertexNormal, specularShininess);
 	}
 	
 	outputColor = sqrt(accumLighting); //2.0 gamma correction

Tut 14 Textures Are Not Pictures/data/main.pdn

Binary file added.

Tut 14 Textures Are Not Pictures/data/main.tga

Binary file added.

Tut 14 Textures Are Not Pictures/tutorials.lua

 	"data/NoCorrectVertexColors.vert",
 	"data/NoCorrectVertexColors.frag")
 
-	--[[
 SetupProject("Tut 14 Material Texture", "Material Texture.cpp",
 	"data/PN.vert",
 	"data/PNT.vert",
 	"data/FixedShininess.frag",
 	"data/TextureShininess.frag")
-	]]
 	

framework/framework.lua

 		objdir "../framework/lib"
 
 		includedirs {"../freeglut-2.6.0/include", "../glload/include",
-			"../glm-0.9.0.7", "../tinyxml", "../framework"}
+			"../glimg/include", "../glm-0.9.0.7", "../tinyxml",
+			"../framework"}
 		
 		configuration "Debug"
 			defines {"DEBUG", "_DEBUG"}
 		files {...}
 
 		includedirs {"../freeglut-2.6.0/include", "../glload/include",
-			"../glm-0.9.0.7", "../tinyxml"}
+			"../glimg/include", "../glm-0.9.0.7", "../tinyxml"}
 			
 		links "framework"
 
 		configuration "Debug"
 			defines {"DEBUG", "_DEBUG"}
 			flags "Symbols"
-			libdirs {"../glload/lib", "../tinyxml/lib"}
+			libdirs {"../glload/lib", "../glimg/lib", "../tinyxml/lib"}
 			links "glloadD"
+			links "glimgD"
 			links "tinyxml_pmD"
 			targetname(projName .. "D")
 		
 		configuration "Release"
 			defines {"RELEASE", "NDEBUG"};
-			libdirs {"../glload/lib", "../tinyxml/lib"}
+			libdirs {"../glload/lib", "../glimg/lib", "../tinyxml/lib"}
 			links "glload"
+			links "glimg"
 			links "tinyxml_pm"
 			targetname(projName)
 

glimg/Test/Test4.lua

+
+project "Test"
+	kind "WindowedApp"
+	language "c++"
+	includedirs { "../include", "../../glload/include" }
+	links {"glload", "glimg"}
+	
+	files {"test.cpp", "test.h"}
+
+	configuration "windows"
+		flags { "WinMain" }
+		defines {"WIN32"}
+		files { "windows.cpp", }
+		links { "OpenGL32" }
+
+	configuration "linux"
+		files { "linux.cpp", }
+		links { "GL" }
+	
+	configuration "Debug"
+		flags "Unicode";
+		defines {"DEBUG", "_DEBUG", "MEMORY_DEBUGGING"};
+		objdir "Debug";
+		flags "Symbols";
+	
+	configuration "Release"
+		defines {"NDEBUG", "RELEASE"};
+		flags "Unicode";
+		flags {"OptimizeSpeed", "NoFramePointer", "ExtraWarnings", "NoEditAndContinue"};
+		objdir "Release";
+

glimg/Test/bitmap.png

Added
New image

glimg/Test/test.cpp

+#include <stdio.h>
+#include <vector>
+#include <glload/gl_3_3_comp.h>
+
+#include <glimg/glimg.h>
+#include <glimg/TextureGenerator.h>
+#include <glimg/TextureGeneratorExceptions.h>
+#include "test.h"
+
+using namespace glimg;
+
+namespace
+{
+	struct TestData
+	{
+		ImageFormat format;
+		unsigned int forceConvertBits;
+	};
+
+	void GetFormats(std::vector<TestData> &formats)
+	{
+		formats.reserve(100);
+
+		TestData testFmt;
+		//Succeed. GL_RGBA8 = 0x8058
+		testFmt.format.eType = DT_NORM_UNSIGNED_INTEGER;
+		testFmt.format.eFormat = FMT_COLOR_RGBA;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PACKED_32_BIT_8888;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Succeed. GL_SRGB8_ALPHA8 = 0x8C43. From forced colorspace.
+		testFmt.format.eType = DT_NORM_UNSIGNED_INTEGER;
+		testFmt.format.eFormat = FMT_COLOR_RGBA;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PACKED_32_BIT_8888;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = FORCE_SRGB_COLORSPACE;
+		formats.push_back(testFmt);
+
+		//Succeed. GL_RGB5_A1 = 0x8057.
+		testFmt.format.eType = DT_NORM_UNSIGNED_INTEGER;
+		testFmt.format.eFormat = FMT_COLOR_RGBA;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PACKED_16_BIT_5551;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Fail. Packed format with RED.
+		testFmt.format.eType = DT_NORM_UNSIGNED_INTEGER;
+		testFmt.format.eFormat = FMT_COLOR_RED;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PACKED_16_BIT_5551;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Fail. Packed format with RG.
+		testFmt.format.eType = DT_NORM_UNSIGNED_INTEGER;
+		testFmt.format.eFormat = FMT_COLOR_RG;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PACKED_16_BIT_5551;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Succeed. GL_SRGB8_ALPHA8 = 0x8C43.
+		testFmt.format.eType = DT_NORM_UNSIGNED_INTEGER;
+		testFmt.format.eFormat = FMT_COLOR_RGBA_sRGB;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PACKED_16_BIT_5551;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Fail. Wrong bitdepth for floats.
+		testFmt.format.eType = DT_FLOAT;
+		testFmt.format.eFormat = FMT_COLOR_RGBA;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PACKED_32_BIT_8888;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Succeed. GL_RGBA16F = 0x881A.
+		testFmt.format.eType = DT_FLOAT;
+		testFmt.format.eFormat = FMT_COLOR_RGBA;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PER_COMP_16;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Succeed. GL_RG16F = 0x822F.
+		testFmt.format.eType = DT_FLOAT;
+		testFmt.format.eFormat = FMT_COLOR_RG;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PER_COMP_16;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Succeed. GL_LUMINANCE_ALPHA16F_ARB = 0x881F. Force Luminance.
+		testFmt.format.eType = DT_FLOAT;
+		testFmt.format.eFormat = FMT_COLOR_RG;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PER_COMP_16;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = FORCE_LUMINANCE_FORMATS;
+		formats.push_back(testFmt);
+
+		//Succeed. GL_R11F_G11F_B10F = 0x8C3A.
+		testFmt.format.eType = DT_FLOAT;
+		testFmt.format.eFormat = FMT_COLOR_RGB;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PACKED_32_BIT_101111_REV;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Failed. Bad order.
+		testFmt.format.eType = DT_COMPRESSED_BC1;
+		testFmt.format.eFormat = FMT_COLOR_RGB;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_COMPRESSED;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Failed. Bad bitdepth.
+		testFmt.format.eType = DT_COMPRESSED_BC1;
+		testFmt.format.eFormat = FMT_COLOR_RGB;
+		testFmt.format.eOrder = ORDER_COMPRESSED;
+		testFmt.format.eBitdepth = BD_PER_COMP_8;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Succeeded. GL_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0
+		testFmt.format.eType = DT_COMPRESSED_BC1;
+		testFmt.format.eFormat = FMT_COLOR_RGB;
+		testFmt.format.eOrder = ORDER_COMPRESSED;
+		testFmt.format.eBitdepth = BD_COMPRESSED;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Succeeded. GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1
+		testFmt.format.eType = DT_COMPRESSED_BC1;
+		testFmt.format.eFormat = FMT_COLOR_RGBA;
+		testFmt.format.eOrder = ORDER_COMPRESSED;
+		testFmt.format.eBitdepth = BD_COMPRESSED;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Succeeded. GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D
+		testFmt.format.eType = DT_COMPRESSED_BC1;
+		testFmt.format.eFormat = FMT_COLOR_RGB;
+		testFmt.format.eOrder = ORDER_COMPRESSED;
+		testFmt.format.eBitdepth = BD_COMPRESSED;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = FORCE_BC1_ALPHA_TEXTURE | FORCE_SRGB_COLORSPACE;
+		formats.push_back(testFmt);
+
+		//Fail. Packed + integral = bad.
+		testFmt.format.eType = DT_SIGNED_INTEGRAL;
+		testFmt.format.eFormat = FMT_COLOR_RGBA;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PACKED_16_BIT_5551;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Succeed. GL_RGBA8I = 0x8D8E.
+		testFmt.format.eType = DT_SIGNED_INTEGRAL;
+		testFmt.format.eFormat = FMT_COLOR_RGBA;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PER_COMP_8;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Succeed. GL_RGB32I = 0x8D83.
+		testFmt.format.eType = DT_SIGNED_INTEGRAL;
+		testFmt.format.eFormat = FMT_COLOR_RGB;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PER_COMP_32;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+
+		//Succeed. GL_RGBA8_SNORM = 0x8F97
+		testFmt.format.eType = DT_NORM_SIGNED_INTEGER;
+		testFmt.format.eFormat = FMT_COLOR_RGBA;
+		testFmt.format.eOrder = ORDER_RGBA;
+		testFmt.format.eBitdepth = BD_PER_COMP_8;
+		testFmt.format.lineAlignment = 4;
+		testFmt.forceConvertBits = 0;
+		formats.push_back(testFmt);
+	}
+}
+
+
+void TestImageFormats()
+{
+	std::vector<TestData> formats;
+	GetFormats(formats);
+
+	for(size_t loop = 0; loop < formats.size(); loop++)
+	{
+		try
+		{
+			GLuint internalFmt = glimg::GetInternalFormat(formats[loop].format, formats[loop].forceConvertBits);
+			OpenGLUploadData upload = glimg::GetUploadFormatType(formats[loop].format, formats[loop].forceConvertBits);
+			printf("Internal Format of %i: 0x%04x, [format=0x%04x, type=0x%04x]\n", loop, internalFmt,
+				upload.format, upload.type);
+		}
+		catch(TextureGenerationException &e)
+		{
+			printf("---->Format %i failed:\n%s\n", loop, e.what());
+		}
+	}
+}
+

glimg/Test/test.h

+#ifndef GLIMG_PRGRAM_TESTER_H
+#define GLIMG_PRGRAM_TESTER_H
+
+void TestImageFormats();
+
+#endif //GLIMG_PRGRAM_TESTER_H

glimg/Test/windows.cpp

+/*
+*		This Code Was Created By Jeff Molofee 2000
+*		A HUGE Thanks To Fredric Echols For Cleaning Up
+*		And Optimizing This Code, Making It More Flexible!
+*		If You've Found This Code Useful, Please Let Me Know.
+*		Visit My Site At nehe.gamedev.net
+*/
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <io.h>
+#include <iostream>
+#include <fstream>
+#include <windows.h>
+#include <tchar.h>
+#include <glload/gl_3_3_comp.h>
+#include <glload/wgl_exts.h>
+#include <glload/gll.h>
+
+#include <glimg/glimg.h>
+#include <glimg/TextureGenerator.h>
+#include "test.h"
+
+HDC			hDC=NULL;		// Private GDI Device Context
+HGLRC		hRC=NULL;		// Permanent Rendering Context
+HWND		hWnd=NULL;		// Holds Our Window Handle
+HINSTANCE	hInstance;		// Holds The Instance Of The Application
+
+bool	keys[256];			// Array Used For The Keyboard Routine
+bool	active=TRUE;		// Window Active Flag Set To TRUE By Default
+bool	fullscreen=TRUE;	// Fullscreen Flag Set To Fullscreen Mode By Default
+
+GLuint texture = 0;
+
+LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);	// Declaration For WndProc
+
+GLvoid ReSizeGLScene(GLsizei width, GLsizei height)		// Resize And Initialize The GL Window
+{
+	if (height==0)										// Prevent A Divide By Zero By
+	{
+		height=1;										// Making Height Equal One
+	}
+
+	glViewport(width / 4, height / 4, width / 2, height / 2);						// Reset The Current Viewport
+
+	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
+	glLoadIdentity();									// Reset The Projection Matrix
+
+	//Give me an orthographic projection.
+	glOrtho(-1, 1, -1, 1, -1, 1);
+
+	glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
+	glLoadIdentity();									// Reset The Modelview Matrix
+}
+
+int InitGL(GLvoid)										// All Setup For OpenGL Goes Here
+{
+	glShadeModel(GL_SMOOTH);							// Enable Smooth Shading
+	glClearColor(1.0f, 1.0f, 1.0f, 0.5f);				// White Background
+	glClearDepth(1.0f);									// Depth Buffer Setup
+	glEnable(GL_DEPTH_TEST);							// Enables Depth Testing
+	glDepthFunc(GL_LEQUAL);								// The Type Of Depth Testing To Do
+	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really Nice Perspective Calculations
+	return TRUE;										// Initialization Went OK
+}
+
+int DrawGLScene(GLvoid)									// Here's Where We Do All The Drawing
+{
+	static bool bFirstTime = true;
+	static GLuint bufferName = 0;
+
+	if(bFirstTime)
+	{
+		bFirstTime = false;
+
+		glGenBuffers(1, &bufferName);
+
+		static int iVal1 = wglext_ARB_multisample;
+
+		iVal1++;
+	}
+
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer
+	glLoadIdentity();									// Reset The Current Modelview Matrix
+
+	glDepthRange(0.0f, 0.5f);
+	glBegin(GL_QUADS);
+	{
+		//Define the color (blue)
+		glColor3ub(0, 0, 255);
+
+		//Draw our four points, clockwise.
+		glVertex3f(-0.5, 0.5, 0);
+		glVertex3f(0.5, 0.5, 0);
+		glVertex3f(0.5, -0.5, 0);
+		glVertex3f(-0.5, -0.5, 0);
+	}
+	glEnd();
+
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(GL_TEXTURE_2D, texture);
+	glEnable(GL_TEXTURE_2D);
+
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+	glDepthRange(0.5f, 1.0f);
+	glBegin(GL_QUADS);
+	{
+		//Gray square.
+		glColor3ub(128, 128, 128);
+
+		//Draw our four points, clockwise.
+		glTexCoord2f(0.0f, 1.0f);
+		glVertex3f(-1, 1, -0.5);
+		glTexCoord2f(1.0f, 1.0f);
+		glVertex3f(1, 1, -0.5);
+		glTexCoord2f(1.0f, 0.0f);
+		glVertex3f(1, -1, 0.5);
+		glTexCoord2f(0.0f, 0.0f);
+		glVertex3f(-1, -1, 0.5);
+	}
+	glEnd();
+
+	glDisable(GL_TEXTURE_2D);
+	glBindTexture(GL_TEXTURE_2D, 0);
+
+	return TRUE;										// Everything Went OK
+}
+
+GLvoid KillGLWindow(GLvoid)								// Properly Kill The Window
+{
+	if (fullscreen)										// Are We In Fullscreen Mode?
+	{
+		ChangeDisplaySettings(NULL,0);					// If So Switch Back To The Desktop
+		ShowCursor(TRUE);								// Show Mouse Pointer
+	}
+
+	if (hRC)											// Do We Have A Rendering Context?
+	{
+		if (!wglMakeCurrent(NULL,NULL))					// Are We Able To Release The DC And RC Contexts?
+		{
+			MessageBox(NULL,_T("Release Of DC And RC Failed."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
+		}
+
+		if (!wglDeleteContext(hRC))						// Are We Able To Delete The RC?
+		{
+			MessageBox(NULL,_T("Release Rendering Context Failed."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
+		}
+		hRC=NULL;										// Set RC To NULL
+	}
+
+	if (hDC && !ReleaseDC(hWnd,hDC))					// Are We Able To Release The DC
+	{
+		MessageBox(NULL,_T("Release Device Context Failed."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
+		hDC=NULL;										// Set DC To NULL
+	}
+
+	if (hWnd && !DestroyWindow(hWnd))					// Are We Able To Destroy The Window?
+	{
+		MessageBox(NULL,_T("Could Not Release hWnd."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
+		hWnd=NULL;										// Set hWnd To NULL
+	}
+
+	if (!UnregisterClass(_T("OpenGL"),hInstance))			// Are We Able To Unregister Class
+	{
+		MessageBox(NULL,_T("Could Not Unregister Class."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
+		hInstance=NULL;									// Set hInstance To NULL
+	}
+}
+
+/*	This Code Creates Our OpenGL Window.  Parameters Are:					*
+*	title			- Title To Appear At The Top Of The Window				*
+*	width			- Width Of The GL Window Or Fullscreen Mode				*
+*	height			- Height Of The GL Window Or Fullscreen Mode			*
+*	bits			- Number Of Bits To Use For Color (8/16/24/32)			*
+*	fullscreenflag	- Use Fullscreen Mode (TRUE) Or Windowed Mode (FALSE)	*/
+
+BOOL CreateGLWindow(TCHAR* title, int width, int height, int bits, bool fullscreenflag)
+{
+	GLuint		PixelFormat;			// Holds The Results After Searching For A Match
+	WNDCLASS	wc;						// Windows Class Structure
+	DWORD		dwExStyle;				// Window Extended Style
+	DWORD		dwStyle;				// Window Style
+	RECT		WindowRect;				// Grabs Rectangle Upper Left / Lower Right Values
+	WindowRect.left=(long)0;			// Set Left Value To 0
+	WindowRect.right=(long)width;		// Set Right Value To Requested Width
+	WindowRect.top=(long)0;				// Set Top Value To 0
+	WindowRect.bottom=(long)height;		// Set Bottom Value To Requested Height
+
+	fullscreen=fullscreenflag;			// Set The Global Fullscreen Flag
+
+	hInstance			= GetModuleHandle(NULL);				// Grab An Instance For Our Window
+	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	// Redraw On Size, And Own DC For Window.
+	wc.lpfnWndProc		= (WNDPROC) WndProc;					// WndProc Handles Messages
+	wc.cbClsExtra		= 0;									// No Extra Window Data
+	wc.cbWndExtra		= 0;									// No Extra Window Data
+	wc.hInstance		= hInstance;							// Set The Instance
+	wc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);			// Load The Default Icon
+	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer
+	wc.hbrBackground	= NULL;									// No Background Required For GL
+	wc.lpszMenuName		= NULL;									// We Don't Want A Menu
+	wc.lpszClassName	= _T("OpenGL");								// Set The Class Name
+
+	if (!RegisterClass(&wc))									// Attempt To Register The Window Class
+	{
+		MessageBox(NULL,_T("Failed To Register The Window Class."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;											// Return FALSE
+	}
+
+	if (fullscreen)												// Attempt Fullscreen Mode?
+	{
+		DEVMODE dmScreenSettings;								// Device Mode
+		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));	// Makes Sure Memory's Cleared
+		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// Size Of The Devmode Structure
+		dmScreenSettings.dmPelsWidth	= width;				// Selected Screen Width
+		dmScreenSettings.dmPelsHeight	= height;				// Selected Screen Height
+		dmScreenSettings.dmBitsPerPel	= bits;					// Selected Bits Per Pixel
+		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
+
+		// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
+		if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
+		{
+			// If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.
+			if (MessageBox(NULL,
+				_T("The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?"),
+				_T("NeHe GL"),MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
+			{
+				fullscreen=FALSE;		// Windowed Mode Selected.  Fullscreen = FALSE
+			}
+			else
+			{
+				// Pop Up A Message Box Letting User Know The Program Is Closing.
+				MessageBox(NULL,_T("Program Will Now Close."),_T("ERROR"),MB_OK|MB_ICONSTOP);
+				return FALSE;									// Return FALSE
+			}
+		}
+	}
+
+	if (fullscreen)												// Are We Still In Fullscreen Mode?
+	{
+		dwExStyle=WS_EX_APPWINDOW;								// Window Extended Style
+		dwStyle=WS_POPUP;										// Windows Style
+		ShowCursor(FALSE);										// Hide Mouse Pointer
+	}
+	else
+	{
+		dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;			// Window Extended Style
+		dwStyle=WS_OVERLAPPEDWINDOW;							// Windows Style
+	}
+
+	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);		// Adjust Window To True Requested Size
+
+	int iScreenWidth = 1280;
+	int iScreenHeight = 720;
+
+	int iWindowPosX = iScreenWidth - (WindowRect.right-WindowRect.left);
+	int iWindowPosY = iScreenHeight - (WindowRect.bottom-WindowRect.top);
+	iWindowPosY -= 100; //Keep it off the bottom.
+
+	// Create The Window
+	if (!(hWnd=CreateWindowEx(	dwExStyle,							// Extended Style For The Window
+		_T("OpenGL"),						// Class Name
+		title,								// Window Title
+		dwStyle |							// Defined Window Style
+		WS_CLIPSIBLINGS |					// Required Window Style
+		WS_CLIPCHILDREN,					// Required Window Style
+		iWindowPosX, iWindowPosY,								// Window Position
+		WindowRect.right-WindowRect.left,	// Calculate Window Width
+		WindowRect.bottom-WindowRect.top,	// Calculate Window Height
+		NULL,								// No Parent Window
+		NULL,								// No Menu
+		hInstance,							// Instance
+		NULL)))								// Dont Pass Anything To WM_CREATE
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Window Creation Error."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
+	{
+		sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
+			1,											// Version Number
+			PFD_DRAW_TO_WINDOW |						// Format Must Support Window
+			PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
+			PFD_DOUBLEBUFFER,							// Must Support Double Buffering
+			PFD_TYPE_RGBA,								// Request An RGBA Format
+			bits,										// Select Our Color Depth
+			0, 0, 0, 0, 0, 0,							// Color Bits Ignored
+			0,											// No Alpha Buffer
+			0,											// Shift Bit Ignored
+			0,											// No Accumulation Buffer
+			0, 0, 0, 0,									// Accumulation Bits Ignored
+			16,											// 16Bit Z-Buffer (Depth Buffer)  
+			0,											// No Stencil Buffer
+			0,											// No Auxiliary Buffer
+			PFD_MAIN_PLANE,								// Main Drawing Layer
+			0,											// Reserved
+			0, 0, 0										// Layer Masks Ignored
+	};
+
+	if (!(hDC=GetDC(hWnd)))							// Did We Get A Device Context?
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Can't Create A GL Device Context."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))	// Did Windows Find A Matching Pixel Format?
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Can't Find A Suitable PixelFormat."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	if(!SetPixelFormat(hDC,PixelFormat,&pfd))		// Are We Able To Set The Pixel Format?
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Can't Set The PixelFormat."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	if (!(hRC=wglCreateContext(hDC)))				// Are We Able To Get A Rendering Context?
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Can't Create A GL Rendering Context."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	if(!wglMakeCurrent(hDC,hRC))					// Try To Activate The Rendering Context
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Can't Activate The GL Rendering Context."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	glload::LoadWinFunctions(hDC);
+	glload::LoadFunctions();
+
+	ShowWindow(hWnd,SW_SHOW);						// Show The Window
+	SetForegroundWindow(hWnd);						// Slightly Higher Priority
+	SetFocus(hWnd);									// Sets Keyboard Focus To The Window
+	ReSizeGLScene(width, height);					// Set Up Our Perspective GL Screen
+
+	if (!InitGL())									// Initialize Our Newly Created GL Window
+	{
+		KillGLWindow();								// Reset The Display
+		MessageBox(NULL,_T("Initialization Failed."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;								// Return FALSE
+	}
+
+	return TRUE;									// Success
+}
+
+LRESULT CALLBACK WndProc(	HWND	hWnd,			// Handle For This Window
+						 UINT	uMsg,			// Message For This Window
+						 WPARAM	wParam,			// Additional Message Information
+						 LPARAM	lParam)			// Additional Message Information
+{
+	switch (uMsg)									// Check For Windows Messages
+	{
+	case WM_ACTIVATE:							// Watch For Window Activate Message
+		{
+			if (!HIWORD(wParam))					// Check Minimization State
+			{
+				active=TRUE;						// Program Is Active
+			}
+			else
+			{
+				active=FALSE;						// Program Is No Longer Active
+			}
+
+			return 0;								// Return To The Message Loop
+		}
+
+	case WM_SYSCOMMAND:							// Intercept System Commands
+		{
+			switch (wParam)							// Check System Calls
+			{
+			case SC_SCREENSAVE:					// Screensaver Trying To Start?
+			case SC_MONITORPOWER:				// Monitor Trying To Enter Powersave?
+				return 0;							// Prevent From Happening
+			}
+			break;									// Exit
+		}
+
+	case WM_CLOSE:								// Did We Receive A Close Message?
+		{
+			PostQuitMessage(0);						// Send A Quit Message
+			return 0;								// Jump Back
+		}
+
+	case WM_KEYDOWN:							// Is A Key Being Held Down?
+		{
+			keys[wParam] = TRUE;					// If So, Mark It As TRUE
+			return 0;								// Jump Back
+		}
+
+	case WM_KEYUP:								// Has A Key Been Released?
+		{
+			keys[wParam] = FALSE;					// If So, Mark It As FALSE
+			return 0;								// Jump Back
+		}
+
+	case WM_SIZE:								// Resize The OpenGL Window
+		{
+			ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));  // LoWord=Width, HiWord=Height
+			return 0;								// Jump Back
+		}
+	}
+
+	// Pass All Unhandled Messages To DefWindowProc
+	return DefWindowProc(hWnd,uMsg,wParam,lParam);
+}
+
+void CreateOurConsoleWindow()
+{
+	int hConHandle;
+	intptr_t lStdHandle;
+	CONSOLE_SCREEN_BUFFER_INFO coninfo;
+	FILE *fp;
+
+	// allocate a console for this app
+	AllocConsole();
+
+	// set the screen buffer to be big enough to let us scroll text
+	GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
+	coninfo.dwSize.Y = 500;
+	SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
+
+	// redirect unbuffered STDOUT to the console
+	lStdHandle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);
+	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
+	fp = _fdopen( hConHandle, "w" );
+	*stdout = *fp;
+	setvbuf( stdout, NULL, _IONBF, 0 );
+
+	// redirect unbuffered STDIN to the console
+	lStdHandle = (intptr_t)GetStdHandle(STD_INPUT_HANDLE);
+	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
+	fp = _fdopen( hConHandle, "r" );
+	*stdin = *fp;
+	setvbuf( stdin, NULL, _IONBF, 0 );
+
+	// redirect unbuffered STDERR to the console
+	lStdHandle = (intptr_t)GetStdHandle(STD_ERROR_HANDLE);
+	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
+	fp = _fdopen( hConHandle, "w" );
+	*stderr = *fp;
+	setvbuf( stderr, NULL, _IONBF, 0 );
+
+	// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
+	std::ios::sync_with_stdio();
+}
+
+void DestroyOurConsoleWindow()
+{
+	FreeConsole();
+}
+
+int WINAPI WinMain(	HINSTANCE	hInstance,			// Instance
+				   HINSTANCE	hPrevInstance,		// Previous Instance
+				   LPSTR		lpCmdLine,			// Command Line Parameters
+				   int			nCmdShow)			// Window Show State
+{
+	MSG		msg;									// Windows Message Structure
+	BOOL	done=FALSE;								// Bool Variable To Exit Loop
+
+	fullscreen = FALSE;							// Windowed Mode
+
+	CreateOurConsoleWindow();
+
+	// Create Our OpenGL Window
+	if (!CreateGLWindow(_T("NeHe's OpenGL Framework"),640,480,32,fullscreen))
+	{
+		return 0;									// Quit If Window Was Not Created
+	}
+
+	TestImageFormats();
+
+//	glimg::ImageSet *pImgSet = glimg::loaders::test::TestImage2D();
+	glimg::ImageSet *pImgSet = glimg::loaders::stb::LoadFromFile("bitmap.png");
+
+	texture = glimg::CreateTexture(pImgSet, 0);
+	glBindTexture(GL_TEXTURE_2D, texture);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glBindTexture(GL_TEXTURE_2D, 0);
+
+	delete pImgSet;
+
+	while(!done)									// Loop That Runs While done=FALSE
+	{
+		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))	// Is There A Message Waiting?
+		{
+			if (msg.message==WM_QUIT)				// Have We Received A Quit Message?
+			{
+				done=TRUE;							// If So done=TRUE
+			}
+			else									// If Not, Deal With Window Messages
+			{
+				TranslateMessage(&msg);				// Translate The Message
+				DispatchMessage(&msg);				// Dispatch The Message
+			}
+		}
+		else										// If There Are No Messages
+		{
+			// Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()
+			if (active)								// Program Active?
+			{
+				if (keys[VK_ESCAPE])				// Was ESC Pressed?
+				{
+					done=TRUE;						// ESC Signalled A Quit
+				}
+				else								// Not Time To Quit, Update Screen
+				{
+					DrawGLScene();					// Draw The Scene
+					SwapBuffers(hDC);				// Swap Buffers (Double Buffering)
+				}
+			}
+
+			if (keys[VK_F1])						// Is F1 Being Pressed?
+			{
+				keys[VK_F1]=FALSE;					// If So Make Key FALSE
+				KillGLWindow();						// Kill Our Current Window
+
+				// Recreate Our OpenGL Window
+				if (!CreateGLWindow(_T("NeHe's OpenGL Framework"),640,480,32,fullscreen))
+				{
+					return 0;						// Quit If Window Was Not Created
+				}
+			}
+		}
+	}
+
+	// Shutdown
+	KillGLWindow();									// Kill The Window
+	return ((int)msg.wParam);							// Exit The Program
+}
+
+project("glimg")
+	kind "StaticLib"
+	language "c++"
+	includedirs {"include", "source", "../glload/include"}
+	targetdir "lib"
+
+	files {
+		"include/glimg/*.h",
+		"source/*.h",
+		"source/*.cpp",
+		"source/*.c",
+	};
+
+	configuration "windows"
+		defines {"WIN32"}
+	
+	configuration "linux"
+	    defines {"LOAD_X11"}
+
+	configuration "Debug"
+		flags "Unicode";
+		defines {"DEBUG", "_DEBUG", "MEMORY_DEBUGGING"};
+		objdir "Debug";
+		flags "Symbols";
+		targetname "glimgD";
+
+	configuration "Release"
+		defines {"NDEBUG", "RELEASE"};
+		flags "Unicode";
+		flags {"OptimizeSpeed", "NoFramePointer", "ExtraWarnings", "NoEditAndContinue"};
+		objdir "Release";
+		targetname "glimg"

glimg/include/glimg/ImageCreator.h

+
+#ifndef GLIMG_IMAGE_CREATOR_H
+#define GLIMG_IMAGE_CREATOR_H
+
+#include <string>
+#include <vector>
+#include <exception>
+#include "ImageSet.h"
+#include "ImageCreatorExceptions.h"
+
+namespace glimg
+{
+	namespace detail
+	{
+		struct SimpleImage
+		{
+			const void *pData;
+			int arrayIx;
+			int mipmapIx;
+			int faceIx;
+		};
+
+		struct FullLayerImage
+		{
+			const void *pData;
+			int mipmapIx;
+		};
+	}
+
+	class MemoryObject
+	{
+	public:
+		virtual ~MemoryObject() {}
+	};
+
+	class ImageCreator
+	{
+	public:
+		ImageCreator(MemoryObject *pObject, Dimensions dimensions, int arrayCount, int mipmapCount,
+			int faceCount, ImageFormat format);
+
+		~ImageCreator();
+
+		void AddImage(const void *pixelData, int arrayIx, int mipmapIx, int faceIx);
+
+		//Adds an array of image data in a single go, specifying an entire mipmap layer.
+		//The expected order of the image data is as follows. Each array in the image
+		//contain X faces, where X is the faceCount.
+		void AddImage(const void *pixelData, int mipmapIx);
+
+		ImageSet *CreateImage();
+
+	private:
+		Dimensions m_dimensions;
+		ImageFormat m_format;
+		MemoryObject *m_pObject;
+		int m_arrayCount;
+		int m_mipmapCount;
+		int m_faceCount;
+
+		std::vector<detail::SimpleImage> m_simpleImages;
+		std::vector<detail::FullLayerImage> m_fullLayerImages;
+	};
+}
+
+
+#endif //GLIMG_IMAGE_CREATOR_H

glimg/include/glimg/ImageCreatorExceptions.h

+
+#ifndef GLIMG_IMAGE_CREATOR_EXCEPTIONS_H
+#define GLIMG_IMAGE_CREATOR_EXCEPTIONS_H
+
+#include <exception>
+
+namespace glimg
+{
+	class ImageCreationException : public std::exception
+	{
+	public:
+
+		virtual const char *what() {return message.c_str();}
+
+	protected:
+		std::string message;
+	};
+
+	class InvalidImageFormatException : public ImageCreationException
+	{
+	public:
+		InvalidImageFormatException()
+		{
+			message = "ImageCreator was given an invalid image format.";
+		}
+
+		explicit InvalidImageFormatException(const std::string &msg)
+		{
+			message = "ImageCreator was given an invalid image format.";
+			message += msg;
+		}
+	};
+
+	class MissingImageException : public ImageCreationException
+	{
+	public:
+		MissingImageException()
+		{
+			message = "ImageCreator is missing one or more images.";
+		}
+	};
+
+	class ArrayOutOfBoundsException : public ImageCreationException
+	{
+	public:
+		ArrayOutOfBoundsException()
+		{
+			message = "Attempted to add an image to an array index that doesn't exist.";
+		}
+	};
+
+	class MipmapLayerOutOfBoundsException : public ImageCreationException
+	{
+	public:
+		MipmapLayerOutOfBoundsException()
+		{
+			message = "Attempted to add an image to a mipmap layer that doesn't exist.";
+		}
+	};
+
+	class FaceIndexOutOfBoundsException : public ImageCreationException
+	{
+	public:
+		FaceIndexOutOfBoundsException()
+		{
+			message = "Attempted to add an image to a face index that doesn't exist.";
+		}
+	};
+
+	class ImageAlreadySpecifiedException : public ImageCreationException
+	{
+	public:
+		ImageAlreadySpecifiedException()
+		{
+			message = "Attempted to add an image that already has been added.";
+		}
+	};
+
+	class ImageSetAlreadyCreatedException : public ImageCreationException
+	{
+	public:
+		ImageSetAlreadyCreatedException()
+		{
+			message = "Attempted to add an image to an ImageCreator that has already been used to create an image set.";
+		}
+	};
+}
+
+
+#endif //GLIMG_IMAGE_CREATOR_EXCEPTIONS_H

glimg/include/glimg/ImageFormat.h

+#ifndef GLIMG_IMAGE_FORMAT_H
+#define GLIMG_IMAGE_FORMAT_H
+
+#include <string>
+
+namespace glimg
+{
+	/**
+	\brief Describes the basic type of the pixel data.
+
+	The pixel data type of an image represents the basic type of data stored in the image.
+	This can be floating-point, normalized unsigned integer, and the like.
+
+	Compressed formats do not have pixel bitdepths or component ordering.
+	**/
+	enum BaseDataType
+	{
+		DT_NORM_UNSIGNED_INTEGER,			///<Image data are unsigned integers that is mapped to floats on the range [0, 1].
+		DT_NORM_SIGNED_INTEGER,				///<Image data are signed integers that is mapped to floats on the range [-1, 1].
+		DT_UNSIGNED_INTEGRAL,				///<Image data are unsigned integers.
+		DT_SIGNED_INTEGRAL,					///<Image data are signed integers.
+		DT_FLOAT,							///<Image data are individual floating-point numbers.
+		DT_SHARED_EXP_FLOAT,				///<Image data are floats, but each pixel uses the same exponent.
+		DT_NUM_UNCOMPRESSED_TYPES,
+
+		DT_COMPRESSED_BC1 = DT_NUM_UNCOMPRESSED_TYPES,	///<Image data is compressed with DXT1/BC1 compression. Unsigned normalized integers.
+		DT_COMPRESSED_BC2,					///<Image data is compressed with DXT3/BC2 compression. Unsigned normalized integers.
+		DT_COMPRESSED_BC3,					///<Image data is compressed with DXT5/BC3 compression. Unsigned normalized integers.
+		DT_COMPRESSED_UNSIGNED_BC4,			///<Image is compressed with BC4 compression (1-component), with unsigned normalized integers.
+		DT_COMPRESSED_SIGNED_BC4,			///<Image is compressed with BC4 compression (1-component), with signed normalized integers.
+		DT_COMPRESSED_UNSIGNED_BC5,			///<Image is compressed with BC5 compression (2-component), with unsigned normalized integers.
+		DT_COMPRESSED_SIGNED_BC5,			///<Image is compressed with BC5 compression (2-component), with signed normalized integers.
+		DT_COMPRESSED_UNSIGNED_BC6H,		///<Image is compressed with BC6H compression, with unsigned floats [0, +inf).
+		DT_COMPRESSED_SIGNED_BC6H,			///<Image is compressed with BC6H compression, with floats.
+		DT_COMPRESSED_BC7,					///<Image data is compressed with BC7 compression. Unsigned normalized integers.
+
+		DT_NUM_TYPES,
+	};
+
+	/**
+	\brief Describes the meaning of the pixel data stored in the image.
+
+	The base data format of an image represents what kind of data is stored in each pixel. If it is
+	color data, it also describes which color components are stored. The order of these components in
+	the image data is not reflected here.
+	**/
+	enum BaseDataFormat
+	{
+		FMT_COLOR_RED,					///<Image contains 1 color component, namely red.
+		FMT_COLOR_RG,					///<Image contains 2 color components, red and green.
+		FMT_COLOR_RGB,					///<Image contains 3 color components, red, green, and blue.
+		FMT_COLOR_RGBX,					///<Image contains 3 color components, red, green, and blue. There is a fourth component, which takes up space in the data but should be discarded.
+		FMT_COLOR_RGBA,					///<Image contains 4 color components, red, green, blue, and alpha.
+		FMT_COLOR_RGB_sRGB,				///<Image contains 3 color components, which are in the sRGB colorspace.
+		FMT_COLOR_RGBX_sRGB,			///<Image contains 3 color components, which are in the sRGB colorspace. There is a fourth component,  which takes up space in the data but should be discarded.
+		FMT_COLOR_RGBA_sRGB,			///<Image contains 4 color components; the RGB components are in the sRGB colorspace.
+
+		FMT_DEPTH,						///<Image contains a single depth component.
+		FMT_DEPTH_X,					///<Image contains a depth value (unsigned normalized integer) and a second component, who's value is discarded/irrelevant.
+
+		FMT_NUM_FORMATS,
+	};
+
+	/**
+	\brief Specifies the ordering of the component data in the image.
+
+	This enumeration specifies the ordering of the components in the image's values. Values that are
+	missing from the BaseDataFormat are ignored.
+
+	Some combinations of order and bitdepth are not allowed.
+	**/
+	enum ComponentOrder
+	{
+		ORDER_RGBA,
+		ORDER_BGRA,
+		ORDER_RGBE,				///<For DT_SHARED_EXP_FLOAT types. The E is the exponent, and it comes first.
+
+		ORDER_DEPTH_STENCIL,	///<Ordering for depth and depth-stencil image formats.
+
+		ORDER_COMPRESSED,		///<The order is built into the compressed data format.
+
+		ORDER_NUM_ORDERS,
+	};
+
+	/**
+	\brief Specifies the bitdepth for each component of each value.
+
+	Each component of each pixel has a particular bitdepth. The bitdepths specified here
+	are either per-component or specify the size of an entire pixel. The PER_COMP
+	enumerators specify the size of each component.
+
+	So if PER_COMP_16 is used with a RGB format, then each pixel takes up 48 bits.
+	This could be using unsigned integers (shorts) or floats (half-floats).
+
+	The PACKED enumerators are for formats where each component does not have
+	the same bitdepth. The number after PACKED specifies the overall bitdepth
+	of the pixel. PACKED_16_BIT means that the pixel takes up 16 bits.
+	The numbers after represent the bitdepth of the individual components, in the oder
+	specified by the ComponentOrder enumerator.
+	**/
+	enum Bitdepth
+	{
+		BD_COMPRESSED,					///<Used for compressed data types. They do not have a bitdepth.
+
+		BD_PER_COMP_8,					///<Each component takes up 8 bits.
+		BD_PER_COMP_16,					///<Each component takes up 16 bits.
+		BD_PER_COMP_32,					///<Each component takes up 32 bits.
+		BD_NUM_PER_COMPONENT,			
+
+		BD_PACKED_16_BIT_565 = BD_NUM_PER_COMPONENT,///<The first and third components take up 5 bits, while the second takes up 6.
+		BD_PACKED_16_BIT_5551,			///<The first three components take up 5 bits, and the last takes up 1.
+		BD_PACKED_16_BIT_4444,			///<Each component takes up 4 bits.
+
+		BD_PACKED_32_BIT_8888,			///<Each component takes up 8 bits.
+		BD_PACKED_32_BIT_1010102,		///<The first three components take up 10 bits, and the last takes up 2.
+		BD_PACKED_32_BIT_248,			///<The first component takes up 24 bits; the second takes up 8 bits.
+
+		BD_PACKED_16_BIT_565_REV,		///<Reverse order. The first and third components take up 5 bits, while the second takes up 6.
+		BD_PACKED_16_BIT_1555_REV,		///<Reverse order. The first three components take up 5 bits, and the last takes up 1.
+		BD_PACKED_16_BIT_4444_REV,		///<Reverse order. Each component takes up 4 bits.
+
+		BD_PACKED_32_BIT_8888_REV,		///<Reverse order. Each component takes up 8 bits.
+		BD_PACKED_32_BIT_2101010_REV,	///<Reverse order. The first three components take up 10 bits, and the last takes up 2.
+		BD_PACKED_32_BIT_101111_REV,	///<Reverse order. The first two components take 11 bits, and the third takes 10. Used for DT_FLOAT types.
+		BD_PACKED_32_BIT_5999_REV,		///<Reverse order. The first 3 components take 9 bits, and the last takes 5. Used for DT_SHARED_EXP_FLOAT types. 
+
+		BD_NUM_BITDEPTH,
+	};
+
+	struct ImageFormat
+	{
+		BaseDataType eType;
+		BaseDataFormat eFormat;
+		ComponentOrder eOrder;
+		Bitdepth eBitdepth;
+
+		int lineAlignment;
+
+		bool ValidateFormat() const;
+		std::string ValidateFormatText() const;
+	};
+
+}
+
+
+#endif //GLIMG_IMAGE_FORMAT_H

glimg/include/glimg/ImageSet.h

+
+#ifndef GLIMG_IMAGE_SET_H
+#define GLIMG_IMAGE_SET_H
+
+#include "ImageFormat.h"
+
+namespace glimg
+{
+	struct Dimensions
+	{
+		int numDimensions;
+		int width;
+		int height;
+		int depth;
+	};
+
+	namespace detail
+	{
+		class ImageSetImpl;
+	}
+
+	class ImageSet;
+
+	/**
+	\brief Represents a single image of a certain dimensionality.
+	**/
+	class Image
+	{
+	public:
+		~Image();
+
+		Dimensions GetDimensions() const;
+
+		ImageFormat GetFormat() const;
+
+		const void *GetImageData() const;
+
+	private:
+		const detail::ImageSetImpl *m_pImpl;
+		int m_arrayIx;
+		int m_faceIx;
+		int m_mipmapLevel;
+
+		friend class detail::ImageSetImpl;
+		friend class ImageSet;
+
+		Image(const detail::ImageSetImpl *pImpl, int arrayIx, int faceIx, int mipmapLevel);
+	};
+
+	/**
+	\brief Represents a set of images that can be stored in a texture object.
+
+	This class represents the full range of possible image layouts with regard to texture objects. All
+	images in the ImageSet use the same format.
+	**/
+	class ImageSet
+	{
+	public:
+		~ImageSet();
+
+		/**
+		\brief Returns the number of dimensions in this image set, as well as the size of the base mipmap image.
+		
+		This function will return the number of dimensions that the images in the image set contains.
+		It also returns the size in pixels of the base image. For dimensions less than 3,
+		the base image size will be 0 for the dimensions that aren't present. For example, if
+		the image is 2D, the ImageDimensions::depth will be zero.
+		**/
+		Dimensions GetDimensions() const;
+
+		/**
+		\brief Returns the number of array images this image set has.
+
+		This function will return the number of array images in the image set. The minimum is 1.
+
+		The API makes no distinction between an array of length 1 and a non-array texture.
+		If such a distinction needs to be made, it should be made in the uploading, not in the storage.
+		**/
+		int GetArrayCount() const;
+
+		/**
+		\brief Returns the number of mipmap levels the image set contains.
+
+		This function will return the number of mipmap levels in the image set. The minimum is 1.
+		
+		**/
+		int GetMipmapCount() const;
+
+		/**
+		\brief Returns the number of faces in the image set.
+
+		This function will return the number of faces in the image set. This will be 1 for regular
+		images, and 6 for cubemaps and cubemap arrays.
+		**/
+		int GetFaceCount() const;
+
+		/**
+		\brief Retrieves the image format that describes all images in this ImageSet.
+		
+		**/
+		ImageFormat GetFormat() const;
+
+		/**
+		\brief Retrieves the image at the given array index, face index, and mipmap level.
+		
+		\return A pointer to the image. Do not use it after the ImageSet object is destroyed. This pointer must be deleted manually.
+		**/
+		Image *GetImage(int ixMipmapLevel, int ixArray = 0, int ixFace = 0) const;
+
+		/**
+		\brief Retrieves a pointer to the full array data for a mipmap level.
+		
+		\return A pointer to the image data. DO NOT DELETE THIS POINTER. Also, do not use this pointer after this object is destroyed.
+		**/
+		const void *GetImageArray(int ixMipmapLevel) const;
+
+	private:
+		detail::ImageSetImpl *m_pImpl;
+
+		explicit ImageSet(detail::ImageSetImpl *pImpl);
+
+		friend class ImageCreator;
+		friend void CreateTexture(unsigned int textureName, const ImageSet *pImage, unsigned int forceConvertBits);
+	};
+}
+
+
+#endif //GLIMG_IMAGE_SET_H

glimg/include/glimg/Loaders.h

+#ifndef GLIMG_LOADERS_H
+#define GLIMG_LOADERS_H
+
+
+#include "TestLoader.h"
+#include "StbLoader.h"
+
+
+#endif //GLIMG_LOADERS_H

glimg/include/glimg/StbLoader.h

+#ifndef GLIMG_STB_LOADER_H
+#define GLIMG_STB_LOADER_H
+
+#include <string>
+#include "ImageSet.h"
+
+namespace glimg
+{
+	namespace loaders
+	{
+		namespace stb
+		{
+			class StbLoaderException : public std::exception
+			{
+			public:
+
+				virtual const char *what() {return message.c_str();}
+
+			protected:
+				std::string message;
+			};
+
+			class UnableToLoadException : public StbLoaderException
+			{
+			public:
+				UnableToLoadException()
+				{
+					message = "The memory buffer could not be loaded by STB_image.";
+				}
+
+				explicit UnableToLoadException(const std::string filename)
+				{
+					message = "The file " + filename + " could not be loaded by STB_image.";
+				}
+			};
+
+			ImageSet *LoadFromFile(const std::string &filename);
+			ImageSet *LoadFromMemory(const unsigned char *buffer, size_t bufSize);
+		}
+	}
+}
+
+
+#endif //GLIMG_STB_LOADER_H

glimg/include/glimg/TestLoader.h

+
+#ifndef GLIMG_TEST_LOADER_H
+#define GLIMG_TEST_LOADER_H
+
+#include "ImageSet.h"
+
+namespace glimg
+{
+	namespace loaders
+	{
+		namespace test
+		{
+			glimg::ImageSet *TestImage2D();
+		}
+	}
+}
+
+
+
+#endif //GLIMG_TEST_LOADER_H

glimg/include/glimg/TextureGenerator.h

+#ifndef GLIMG_TEXTURE_GENERATOR_H
+#define GLIMG_TEXTURE_GENERATOR_H
+
+#include "ImageSet.h"
+
+
+namespace glimg
+{
+	enum ForcedConvertBits
+	{
+		FORCE_SRGB_COLORSPACE		= 0x0001,	///<When possible, will force the format to use the sRGB colorspace. Does not cause erroring for formats that can't be sRGB, unless your GL implementation doesn't support sRGB.
+		FORCE_BC1_ALPHA_TEXTURE		= 0x0002,	///<When used with a BC1 texture, will force the texture to have an alpha.
+		FORCE_ARRAY_TEXTURE			= 0x0004,	///<The texture will be an array texture even if the depth is one. Ignored for formats that can't be arrays. Will throw if array textures of that type are not supported (ie: cubemap arrays, 2D arrays for lesser hardware, etc).
+		FORCE_LUMINANCE_FORMATS		= 0x0008,	///<Red and RG textures will become luminance and luminance/alpha textures in all cases. Exceptions will be thrown if the GL implementation does not support those luminance/alpha formats.
+
+		FORCE_REQUIRED_FORMATS		= 0x0010,	///<Will only get image formats that are required to exist by OpenGL.
+		FORCE_INTEGRAL_FORMAT		= 0x0020,	///<Integer textures are considered integral.
+		FORCE_SIGNED_FORMAT			= 0x0040,	///<Unsigned integer textures are considered signed integers.
+		FORCE_COLOR_RENDERABLE		= 0x0080,	///<Will force the use of formats that are required to be valid render targets. This will add components if necessary, but it will throw if conversion would require fundamentally changing the basic format (from signed to unsigned, compressed textures, etc).
+	};
+
+	unsigned int GetInternalFormat(const ImageFormat &format, unsigned int forceConvertBits);
+
+	struct OpenGLUploadData
+	{
+		unsigned int format;
+		unsigned int type;
+	};
+
+	OpenGLUploadData GetUploadFormatType(const ImageFormat &format, unsigned int forceConvertBits);
+
+	//Will not change OpenGL state in the event of an exception.
+	//Will always return a texture-complete texture.
+	unsigned int CreateTexture(const ImageSet *pImage, unsigned int forceConvertBits);
+	void CreateTexture(unsigned int textureName, const ImageSet *pImage, unsigned int forceConvertBits);
+}
+
+
+
+#endif //GLIMG_TEXTURE_GENERATOR_H

glimg/include/glimg/TextureGeneratorExceptions.h

+#ifndef GLIMG_TEXTURE_GENERATOR_EXCEPTIONS_H
+#define GLIMG_TEXTURE_GENERATOR_EXCEPTIONS_H
+
+#include <exception>
+#include <string>
+
+namespace glimg
+{
+	class TextureGenerationException : public std::exception
+	{
+	public:
+
+		virtual const char *what() {return message.c_str();}
+
+	protected:
+		std::string message;
+	};
+
+	class ImageFormatUnsupportedException : public TextureGenerationException
+	{
+	public:
+		ImageFormatUnsupportedException()
+		{
+			message = "The image format is not supported by this OpenGL implementation.";
+		}
+
+		explicit ImageFormatUnsupportedException(const std::string &msg)
+		{
+			message = "The image format is not supported by this OpenGL implementation for this reason:\n";
+			message += msg;
+		}
+	};
+
+	class TextureUnsupportedException : public TextureGenerationException
+	{
+	public:
+		TextureUnsupportedException()
+		{
+			message = "The texture type is not supported by this OpenGL implementation.";
+		}
+
+		explicit TextureUnsupportedException(const std::string &msg)
+		{
+			message = "The texture type is not supported by this OpenGL implementation for this reason:\n";
+			message += msg;
+		}
+	};
+
+	class TextureUnexpectedException : public TextureGenerationException
+	{
+	public:
+		TextureUnexpectedException()
+		{
+			message = "The texture type is not supported by glimg at this time.";
+		}
+
+		explicit TextureUnexpectedException(const std::string &msg)
+		{
+			message = "The texture type is not supported by glimg at this time:\n";
+			message += msg;
+		}
+	};
+
+	class CannotForceRenderTargetException : public TextureGenerationException
+	{
+	public:
+		CannotForceRenderTargetException()
+		{
+			message = "The image format cannot be forced to be a renderable format without compromising the data.";
+		}
+	};
+
+	class ImageFormatUnexpectedException : public TextureGenerationException
+	{
+	public:
+		ImageFormatUnexpectedException()
+		{
+			message = "This image format is not supported by glimg.\nNo idea how we got here.";
+		}
+
+		explicit ImageFormatUnexpectedException(const std::string &msg)
+		{
+			message = "This image format is not supported by glimg.\n";
+			message += msg;
+		}
+	};
+
+}
+
+
+
+#endif //GLIMG_TEXTURE_GENERATOR_EXCEPTIONS_H

glimg/include/glimg/glimg.h

+#ifndef GLIMG_GLIMG_H
+#define GLIMG_GLIMG_H
+
+#include "ImageSet.h"
+#include "Loaders.h"
+
+#endif //GLIMG_GLIMG_H

glimg/premake4.lua

+
+solution "glimg"
+configurations {"Debug", "Release"}
+defines {"_CRT_SECURE_NO_WARNINGS"}
+defines {"_SCL_SECURE_NO_WARNINGS"}
+
+dofile("glimg.lua")
+dofile("../glload/glload.lua");
+dofile("Test/Test4.lua");

glimg/source/ImageCreator.cpp

+
+#include <assert.h>
+#include <algorithm>
+#include "glimg/ImageSet.h"
+#include "glimg/ImageCreator.h"
+#include "ImageSetImpl.h"
+
+namespace glimg
+{
+	ImageCreator::ImageCreator( MemoryObject *pObject, Dimensions dimensions,
+		int arrayCount, int mipmapCount, int faceCount, ImageFormat format )
+		: m_dimensions(dimensions)
+		, m_format(format)
+		, m_pObject(pObject)
+		, m_arrayCount(arrayCount)
+		, m_mipmapCount(mipmapCount)
+		, m_faceCount(faceCount)
+	{
+		assert(m_pObject);
+		assert(m_faceCount == 6 || m_faceCount == 1);
+
+		const std::string &msg = m_format.ValidateFormatText();
+		if(!msg.empty())
+		{
+			delete(m_pObject);
+			throw InvalidImageFormatException(msg);
+		}
+	}
+
+	ImageCreator::~ImageCreator()
+	{
+		if(m_pObject)
+			delete m_pObject;
+	}
+
+	namespace
+	{
+		struct MipmapPred
+		{
+			MipmapPred(int _mipmapIx) : mipmapIx(_mipmapIx) {}
+
+			bool operator()(const detail::SimpleImage &img)
+			{
+				return img.mipmapIx == mipmapIx;
+			}
+
+			bool operator()(const detail::FullLayerImage &img)
+			{
+				return img.mipmapIx == mipmapIx;
+			}
+
+			int mipmapIx;
+		};
+
+		struct ImagePred
+		{
+			ImagePred(int _arrayIx, int _mipmapIx, int _faceIx)
+				: arrayIx(_arrayIx), mipmapIx(_mipmapIx), faceIx(_faceIx)
+			{}
+			
+			bool operator()(const detail::SimpleImage &img)
+			{
+				return
+					(img.arrayIx == arrayIx) && 
+					(img.mipmapIx == mipmapIx) && 
+					(img.faceIx == faceIx);
+			}
+
+			int arrayIx;
+			int mipmapIx;
+			int faceIx;
+		};
+	}
+
+	void ImageCreator::AddImage( const void *pixelData, int arrayIx, int mipmapIx, int faceIx )
+	{
+		if(!m_pObject)
+			throw ImageSetAlreadyCreatedException();
+
+		//Check inputs.
+		if((arrayIx < 0) || (m_arrayCount <= arrayIx))
+			throw ArrayOutOfBoundsException();
+
+		if((mipmapIx < 0) || (m_mipmapCount <= mipmapIx))
+			throw MipmapLayerOutOfBoundsException();
+
+		if((faceIx < 0) || (m_mipmapCount <= faceIx))
+			throw MipmapLayerOutOfBoundsException();
+
+		//Check to see if this image exists.
+		{
+			std::vector<detail::FullLayerImage>::iterator found =
+				std::find_if(m_fullLayerImages.begin(), m_fullLayerImages.end(), MipmapPred(mipmapIx));
+
+			if(found != m_fullLayerImages.end())
+				throw ImageAlreadySpecifiedException();
+		}
+
+		{
+			std::vector<detail::SimpleImage>::iterator found =
+				std::find_if(m_simpleImages.begin(), m_simpleImages.end(),
+				ImagePred(arrayIx, mipmapIx, faceIx));
+
+			if(found != m_simpleImages.end())
+				throw ImageAlreadySpecifiedException();
+		}
+
+		//The image can now be added.
+		detail::SimpleImage newData;
+		newData.arrayIx = arrayIx;
+		newData.mipmapIx = mipmapIx;
+		newData.faceIx = faceIx;
+		newData.pData = pixelData;
+
+		m_simpleImages.push_back(newData);
+	}
+
+	void ImageCreator::AddImage( const void *pixelData, int mipmapIx )
+	{
+		if(!m_pObject)
+			throw ImageSetAlreadyCreatedException();
+
+		//Check inputs.
+		if((mipmapIx < 0) || (m_mipmapCount <= mipmapIx))
+			throw MipmapLayerOutOfBoundsException();
+
+		//Check to see if this image exists.
+		{
+			std::vector<detail::FullLayerImage>::iterator found =
+				std::find_if(m_fullLayerImages.begin(), m_fullLayerImages.end(), MipmapPred(mipmapIx));
+
+			if(found != m_fullLayerImages.end())
+				throw ImageAlreadySpecifiedException();
+		}
+
+		{
+			std::vector<detail::SimpleImage>::iterator found =
+				std::find_if(m_simpleImages.begin(), m_simpleImages.end(),
+				MipmapPred(mipmapIx));
+
+			if(found != m_simpleImages.end())
+				throw ImageAlreadySpecifiedException();
+		}
+
+		//The image can now be added.
+		detail::FullLayerImage newData;
+		newData.mipmapIx = mipmapIx;
+		newData.pData = pixelData;
+
+		m_fullLayerImages.push_back(newData);
+	}
+
+	ImageSet * ImageCreator::CreateImage()
+	{
+		std::vector<detail::MipmapLevel> mipmapList;
+		mipmapList.resize(m_mipmapCount);
+
+		//Make sure that we have all of the images we should.
+		//Also, build the mipmap data pointer list.
+		for(int mipmapIx = 0; mipmapIx < m_mipmapCount; mipmapIx++)
+		{
+			detail::MipmapLevel &mipmap = mipmapList[mipmapIx];
+
+			std::vector<detail::FullLayerImage>::iterator found =
+				std::find_if(m_fullLayerImages.begin(), m_fullLayerImages.end(), MipmapPred(mipmapIx));
+
+			if(found != m_fullLayerImages.end())
+			{
+				//Add this to the list.
+				mipmap.bFullLayer = true;
+				detail::PixelData pixelData;
+				pixelData.pPixelData = found->pData;
+				mipmap.fullPixelData = pixelData;
+			}
+			else
+			{
+				mipmap.bFullLayer = false;
+				detail::PixelData pixelData;
+				pixelData.pPixelData = NULL;
+				mipmap.fullPixelData = pixelData;
+				mipmap.individualDataList.reserve(m_arrayCount * m_faceCount);
+
+				//Find all of the faces and arrays with this mipmap level in the simple images.
+				int iSubIx = 0;
+				for(int arrayIx = 0; arrayIx < m_arrayCount; arrayIx++)
+				{
+					for(int faceIx = 0; faceIx < m_faceCount; faceIx++)
+					{
+						std::vector<detail::SimpleImage>::iterator found =
+							std::find_if(m_simpleImages.begin(), m_simpleImages.end(),
+							ImagePred(arrayIx, mipmapIx, faceIx));
+