This structure is used to pass to a callback function data that is uniform across all images.
texImage1DCallback(int miplevel, int face,
int width, int height,
int depth,
ktx_uint32_t faceLodSize,
void* pixels, void* userdata)
{
ktx_cbdata* cbData = (ktx_cbdata*)userdata;
assert(pfGlTexImage1D != NULL);
pfGlTexImage1D(cbData->glTarget + face, miplevel,
cbData->glInternalformat, width, 0,
cbData->glFormat, cbData->glType, pixels);
if ((cbData->glError = glGetError()) == GL_NO_ERROR) {
} else {
}
}
compressedTexImage1DCallback(int miplevel, int face,
int width, int height,
int depth,
ktx_uint32_t faceLodSize,
void* pixels, void* userdata)
{
ktx_cbdata* cbData = (ktx_cbdata*)userdata;
assert(pfGlCompressedTexImage1D != NULL);
pfGlCompressedTexImage1D(cbData->glTarget + face, miplevel,
cbData->glInternalformat, width, 0,
faceLodSize, pixels);
if ((cbData->glError = glGetError()) == GL_NO_ERROR) {
} else {
}
}
texImage2DCallback(int miplevel, int face,
int width, int height,
int depth,
ktx_uint32_t faceLodSize,
void* pixels, void* userdata)
{
ktx_cbdata* cbData = (ktx_cbdata*)userdata;
glTexImage2D(cbData->glTarget + face, miplevel,
cbData->glInternalformat, width,
cbData->numLayers == 0 ? height : cbData->numLayers, 0,
cbData->glFormat, cbData->glType, pixels);
if ((cbData->glError = glGetError()) == GL_NO_ERROR) {
} else {
}
}
compressedTexImage2DCallback(int miplevel, int face,
int width, int height,
int depth,
ktx_uint32_t faceLodSize,
void* pixels, void* userdata)
{
ktx_cbdata* cbData = (ktx_cbdata*)userdata;
GLenum glerror;
glCompressedTexImage2D(cbData->glTarget + face, miplevel,
cbData->glInternalformat, width,
cbData->numLayers == 0 ? height : cbData->numLayers,
0,
faceLodSize, pixels);
glerror = glGetError();
#if SUPPORT_SOFTWARE_ETC_UNPACK
if ((glerror == GL_INVALID_ENUM || glerror == GL_INVALID_VALUE)
&& (cbData->glInternalformat == GL_ETC1_RGB8_OES
|| (cbData->glInternalformat >= GL_COMPRESSED_R11_EAC
&& cbData->glInternalformat <= GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC)
))
{
GLubyte* unpacked;
GLenum format, internalformat, type;
result = _ktxUnpackETC((GLubyte*)pixels, cbData->glInternalformat,
width, height, &unpacked,
&format, &internalformat,
&type, R16Formats, supportsSRGB);
return result;
}
if (!(sizedFormats & _NON_LEGACY_FORMATS)) {
if (internalformat == GL_RGB8)
internalformat = GL_RGB;
else if (internalformat == GL_RGBA8)
internalformat = GL_RGBA;
}
glTexImage2D(cbData->glTarget + face, miplevel,
internalformat, width,
cbData->numLayers == 0 ? height : cbData->numLayers, 0,
format, type, unpacked);
free(unpacked);
glerror = glGetError();
}
#endif
if ((cbData->glError = glerror) == GL_NO_ERROR) {
} else {
}
}
texImage3DCallback(int miplevel, int face,
int width, int height,
int depth,
ktx_uint32_t faceLodSize,
void* pixels, void* userdata)
{
ktx_cbdata* cbData = (ktx_cbdata*)userdata;
assert(pfGlTexImage3D != NULL);
pfGlTexImage3D(cbData->glTarget + face, miplevel,
cbData->glInternalformat,
width, height,
cbData->numLayers == 0 ? depth : cbData->numLayers,
0,
cbData->glFormat, cbData->glType, pixels);
if ((cbData->glError = glGetError()) == GL_NO_ERROR) {
} else {
}
}
compressedTexImage3DCallback(int miplevel, int face,
int width, int height,
int depth,
ktx_uint32_t faceLodSize,
void* pixels, void* userdata)
{
ktx_cbdata* cbData = (ktx_cbdata*)userdata;
assert(pfGlCompressedTexImage3D != NULL);
pfGlCompressedTexImage3D(cbData->glTarget + face, miplevel,
cbData->glInternalformat,
width, height,
cbData->numLayers == 0 ? depth : cbData->numLayers,
0,
faceLodSize, pixels);
if ((cbData->glError = glGetError()) == GL_NO_ERROR) {
} else {
}
}
This function creates the GL texture object and sets up the callbacks to load the image data into it.
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#if KTX_OPENGL
#ifdef _WIN32
#include <windows.h>
#undef KTX_USE_GETPROC
#define KTX_USE_GETPROC 1
#else
#if !defined(KTX_USE_GETPROC)
#define KTX_USE_GETPROC 0
#endif
#endif
#if KTX_USE_GETPROC
#include <GL/glew.h>
#else
#define GL_GLEXT_PROTOTYPES
#include <GL/glcorearb.h>
#endif
#define GL_APIENTRY APIENTRY
#include "gl_funcptrs.h"
#elif KTX_OPENGL_ES1
#include <GLES/gl.h>
#include <GLES/glext.h>
#include "gles1_funcptrs.h"
#elif KTX_OPENGL_ES2
#define GL_GLEXT_PROTOTYPES
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include "gles2_funcptrs.h"
#elif KTX_OPENGL_ES3
#define GL_GLEXT_PROTOTYPES
#include <GLES3/gl3.h>
#include <GLES2/gl2ext.h>
#include "gles3_funcptrs.h"
#else
#error Please #define one of KTX_OPENGL, KTX_OPENGL_ES1, KTX_OPENGL_ES2 or KTX_OPENGL_ES3 as 1
#endif
#include "ktxint.h"
DECLARE_GL_FUNCPTRS
#define _CONTEXT_ES_PROFILE_BIT 0x4
#define _NON_LEGACY_FORMATS 0x1
#define _LEGACY_FORMATS 0x2
#define _ALL_SIZED_FORMATS (_NON_LEGACY_FORMATS | _LEGACY_FORMATS)
#define _NO_SIZED_FORMATS 0
static GLint contextProfile = 0;
static GLint sizedFormats = _ALL_SIZED_FORMATS;
static GLboolean supportsSwizzle = GL_TRUE;
static GLint R16Formats = _KTX_ALL_R16_FORMATS;
static GLboolean supportsSRGB = GL_TRUE;
static GLboolean supportsCubeMapArrays = GL_FALSE;
#define glGetString(x) (const char*)glGetString(x)
#define pfGlGetStringi(x,y) (const char*)pfGlGetStringi(x,y)
static GLboolean
hasExtension(const char* extension)
{
if (pfGlGetStringi == NULL) {
if (strstr(glGetString(GL_EXTENSIONS), extension) != NULL)
return GL_TRUE;
else
return GL_FALSE;
} else {
int i, n;
glGetIntegerv(GL_NUM_EXTENSIONS, &n);
for (i = 0; i < n; i++) {
if (strcmp(pfGlGetStringi(GL_EXTENSIONS, i), extension) == 0)
return GL_TRUE;
}
return GL_FALSE;
}
}
static void
discoverContextCapabilities(void)
{
GLint majorVersion = 1;
GLint minorVersion = 0;
INITIALIZE_GL_FUNCPTRS
if (strstr(glGetString(GL_VERSION), "GL ES") != NULL)
contextProfile = _CONTEXT_ES_PROFILE_BIT;
glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
if (glGetError() != GL_NO_ERROR) {
if (contextProfile & _CONTEXT_ES_PROFILE_BIT)
sscanf(glGetString(GL_VERSION), "OpenGL ES %d.%d ",
&majorVersion, &minorVersion);
else
sscanf(glGetString(GL_VERSION), "OpenGL %d.%d ",
&majorVersion, &minorVersion);
}
if (contextProfile & _CONTEXT_ES_PROFILE_BIT) {
if (majorVersion < 3) {
supportsSwizzle = GL_FALSE;
sizedFormats = _NO_SIZED_FORMATS;
R16Formats = _KTX_NO_R16_FORMATS;
supportsSRGB = GL_FALSE;
} else {
sizedFormats = _NON_LEGACY_FORMATS;
if (hasExtension("GL_EXT_texture_cube_map_array")) {
supportsCubeMapArrays = GL_TRUE;
}
}
if (hasExtension("GL_OES_required_internalformat")) {
sizedFormats |= _ALL_SIZED_FORMATS;
}
} else {
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &contextProfile);
if (glGetError() == GL_NO_ERROR) {
if (majorVersion == 3 && minorVersion < 3)
supportsSwizzle = GL_FALSE;
if ((contextProfile & GL_CONTEXT_CORE_PROFILE_BIT))
sizedFormats &= ~_LEGACY_FORMATS;
if (majorVersion >= 4)
supportsCubeMapArrays = GL_TRUE;
} else {
contextProfile = GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
supportsSwizzle = GL_FALSE;
if (majorVersion < 2 && hasExtension("GL_EXT_texture_sRGB")) {
supportsSRGB = GL_FALSE;
}
if (majorVersion == 3) {
if (minorVersion == 0)
R16Formats &= ~_KTX_R16_FORMATS_SNORM;
} else if (hasExtension("GL_ARB_texture_rg")) {
R16Formats &= ~_KTX_R16_FORMATS_SNORM;
} else {
R16Formats = _KTX_NO_R16_FORMATS;
}
}
if (!supportsCubeMapArrays) {
if (hasExtension("GL_ARB_texture_cube_map_array")) {
supportsCubeMapArrays = GL_TRUE;
}
}
}
}
#if SUPPORT_LEGACY_FORMAT_CONVERSION
static void convertFormat(GLenum target, GLenum* pFormat, GLenum* pInternalformat) {
switch (*pFormat) {
case GL_ALPHA:
{
GLint swizzle[] = {GL_ZERO, GL_ZERO, GL_ZERO, GL_RED};
*pFormat = GL_RED;
glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
switch (*pInternalformat) {
case GL_ALPHA:
case GL_ALPHA4:
case GL_ALPHA8:
*pInternalformat = GL_R8;
break;
case GL_ALPHA12:
case GL_ALPHA16:
*pInternalformat = GL_R16;
break;
}
}
case GL_LUMINANCE:
{
GLint swizzle[] = {GL_RED, GL_RED, GL_RED, GL_ONE};
*pFormat = GL_RED;
glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
switch (*pInternalformat) {
case GL_LUMINANCE:
case GL_LUMINANCE4:
case GL_LUMINANCE8:
*pInternalformat = GL_R8;
break;
case GL_LUMINANCE12:
case GL_LUMINANCE16:
*pInternalformat = GL_R16;
break;
#if 0
case GL_SLUMINANCE:
case GL_SLUMINANCE8:
*pInternalformat = GL_SRGB8;
break;
#endif
}
break;
}
case GL_LUMINANCE_ALPHA:
{
GLint swizzle[] = {GL_RED, GL_RED, GL_RED, GL_GREEN};
*pFormat = GL_RG;
glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
switch (*pInternalformat) {
case GL_LUMINANCE_ALPHA:
case GL_LUMINANCE4_ALPHA4:
case GL_LUMINANCE6_ALPHA2:
case GL_LUMINANCE8_ALPHA8:
*pInternalformat = GL_RG8;
break;
case GL_LUMINANCE12_ALPHA4:
case GL_LUMINANCE12_ALPHA12:
case GL_LUMINANCE16_ALPHA16:
*pInternalformat = GL_RG16;
break;
#if 0
case GL_SLUMINANCE_ALPHA:
case GL_SLUMINANCE8_ALPHA8:
*pInternalformat = GL_SRGB8_ALPHA8;
break;
#endif
}
break;
}
case GL_INTENSITY:
{
GLint swizzle[] = {GL_RED, GL_RED, GL_RED, GL_RED};
*pFormat = GL_RED;
glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
switch (*pInternalformat) {
case GL_INTENSITY:
case GL_INTENSITY4:
case GL_INTENSITY8:
*pInternalformat = GL_R8;
break;
case GL_INTENSITY12:
case GL_INTENSITY16:
*pInternalformat = GL_R16;
break;
}
break;
}
default:
break;
}
}
#endif
typedef struct ktx_cbdata {
GLenum glTarget;
GLenum glFormat;
GLenum glInternalformat;
GLenum glType;
GLenum glError;
GLuint numLayers;
} ktx_cbdata;
texImage1DCallback(int miplevel, int face,
int width, int height,
int depth,
ktx_uint32_t faceLodSize,
void* pixels, void* userdata)
{
ktx_cbdata* cbData = (ktx_cbdata*)userdata;
assert(pfGlTexImage1D != NULL);
pfGlTexImage1D(cbData->glTarget + face, miplevel,
cbData->glInternalformat, width, 0,
cbData->glFormat, cbData->glType, pixels);
if ((cbData->glError = glGetError()) == GL_NO_ERROR) {
} else {
}
}
compressedTexImage1DCallback(int miplevel, int face,
int width, int height,
int depth,
ktx_uint32_t faceLodSize,
void* pixels, void* userdata)
{
ktx_cbdata* cbData = (ktx_cbdata*)userdata;
assert(pfGlCompressedTexImage1D != NULL);
pfGlCompressedTexImage1D(cbData->glTarget + face, miplevel,
cbData->glInternalformat, width, 0,
faceLodSize, pixels);
if ((cbData->glError = glGetError()) == GL_NO_ERROR) {
} else {
}
}
texImage2DCallback(int miplevel, int face,
int width, int height,
int depth,
ktx_uint32_t faceLodSize,
void* pixels, void* userdata)
{
ktx_cbdata* cbData = (ktx_cbdata*)userdata;
glTexImage2D(cbData->glTarget + face, miplevel,
cbData->glInternalformat, width,
cbData->numLayers == 0 ? height : cbData->numLayers, 0,
cbData->glFormat, cbData->glType, pixels);
if ((cbData->glError = glGetError()) == GL_NO_ERROR) {
} else {
}
}
compressedTexImage2DCallback(int miplevel, int face,
int width, int height,
int depth,
ktx_uint32_t faceLodSize,
void* pixels, void* userdata)
{
ktx_cbdata* cbData = (ktx_cbdata*)userdata;
GLenum glerror;
glCompressedTexImage2D(cbData->glTarget + face, miplevel,
cbData->glInternalformat, width,
cbData->numLayers == 0 ? height : cbData->numLayers,
0,
faceLodSize, pixels);
glerror = glGetError();
#if SUPPORT_SOFTWARE_ETC_UNPACK
if ((glerror == GL_INVALID_ENUM || glerror == GL_INVALID_VALUE)
&& (cbData->glInternalformat == GL_ETC1_RGB8_OES
|| (cbData->glInternalformat >= GL_COMPRESSED_R11_EAC
&& cbData->glInternalformat <= GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC)
))
{
GLubyte* unpacked;
GLenum format, internalformat, type;
result = _ktxUnpackETC((GLubyte*)pixels, cbData->glInternalformat,
width, height, &unpacked,
&format, &internalformat,
&type, R16Formats, supportsSRGB);
return result;
}
if (!(sizedFormats & _NON_LEGACY_FORMATS)) {
if (internalformat == GL_RGB8)
internalformat = GL_RGB;
else if (internalformat == GL_RGBA8)
internalformat = GL_RGBA;
}
glTexImage2D(cbData->glTarget + face, miplevel,
internalformat, width,
cbData->numLayers == 0 ? height : cbData->numLayers, 0,
format, type, unpacked);
free(unpacked);
glerror = glGetError();
}
#endif
if ((cbData->glError = glerror) == GL_NO_ERROR) {
} else {
}
}
texImage3DCallback(int miplevel, int face,
int width, int height,
int depth,
ktx_uint32_t faceLodSize,
void* pixels, void* userdata)
{
ktx_cbdata* cbData = (ktx_cbdata*)userdata;
assert(pfGlTexImage3D != NULL);
pfGlTexImage3D(cbData->glTarget + face, miplevel,
cbData->glInternalformat,
width, height,
cbData->numLayers == 0 ? depth : cbData->numLayers,
0,
cbData->glFormat, cbData->glType, pixels);
if ((cbData->glError = glGetError()) == GL_NO_ERROR) {
} else {
}
}
compressedTexImage3DCallback(int miplevel, int face,
int width, int height,
int depth,
ktx_uint32_t faceLodSize,
void* pixels, void* userdata)
{
ktx_cbdata* cbData = (ktx_cbdata*)userdata;
assert(pfGlCompressedTexImage3D != NULL);
pfGlCompressedTexImage3D(cbData->glTarget + face, miplevel,
cbData->glInternalformat,
width, height,
cbData->numLayers == 0 ? depth : cbData->numLayers,
0,
faceLodSize, pixels);
if ((cbData->glError = glGetError()) == GL_NO_ERROR) {
} else {
}
}
ktxTexture_GLUpload(
ktxTexture* This, GLuint* pTexture, GLenum* pTarget,
GLenum* pGlerror)
{
GLint previousUnpackAlignment;
GLuint texname;
GLenum target = GL_TEXTURE_2D;
int texnameUser;
PFNKTXITERCB iterCb = NULL;
ktx_cbdata cbData;
int dimensions;
if (pGlerror)
*pGlerror = GL_NO_ERROR;
if (!This) {
}
if (!pTarget) {
}
if (contextProfile == 0)
discoverContextCapabilities();
glGetIntegerv(GL_UNPACK_ALIGNMENT, &previousUnpackAlignment);
}
texnameUser = pTexture && *pTexture;
if (texnameUser) {
texname = *pTexture;
} else {
glGenTextures(1, &texname);
}
dimensions += 1;
target = GL_TEXTURE_CUBE_MAP_ARRAY;
} else {
case 1: target = GL_TEXTURE_1D_ARRAY_EXT; break;
case 2: target = GL_TEXTURE_2D_ARRAY_EXT; break;
default: assert(KTX_TRUE);
}
}
} else {
target = GL_TEXTURE_CUBE_MAP;
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
} else {
case 1: target = GL_TEXTURE_1D; break;
case 2: target = GL_TEXTURE_2D; break;
case 3: target = GL_TEXTURE_3D; break;
default: assert(KTX_TRUE);
}
}
cbData.numLayers = 0;
}
if (target == GL_TEXTURE_1D &&
((This->
isCompressed && (pfGlCompressedTexImage1D == NULL)) ||
{
}
if (target == GL_TEXTURE_3D &&
((This->
isCompressed && (pfGlCompressedTexImage3D == NULL)) ||
{
}
if (target == GL_TEXTURE_CUBE_MAP_ARRAY && !supportsCubeMapArrays) {
}
switch (dimensions) {
case 1:
? compressedTexImage1DCallback : texImage1DCallback;
break;
case 2:
? compressedTexImage2DCallback : texImage2DCallback;
break;
case 3:
? compressedTexImage3DCallback : texImage3DCallback;
break;
default:
assert(KTX_TRUE);
}
glBindTexture(target, texname);
glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE);
}
#ifdef GL_TEXTURE_MAX_LEVEL
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, This->
numLevels - 1);
#endif
if (target == GL_TEXTURE_CUBE_MAP) {
cbData.glTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
} else {
cbData.glTarget = target;
}
#if SUPPORT_LEGACY_FORMAT_CONVERSION
if (sizedFormats == _NON_LEGACY_FORMATS && supportsSwizzle) {
convertFormat(target, &cbData.glFormat, &cbData.glInternalformat);
} else if (sizedFormats == _NO_SIZED_FORMATS)
#else
if (sizedFormats == _NO_SIZED_FORMATS
|| (!(sizedFormats & _LEGACY_FORMATS) &&
}
#endif
}
if (ktxTexture_isActiveStream(This))
result = ktxTexture_IterateLoadLevelFaces(This, iterCb, &cbData);
else
result = ktxTexture_IterateLevelFaces(This, iterCb, &cbData);
if (result !=
KTX_SUCCESS && cbData.glError != GL_NO_ERROR) {
if (pGlerror)
*pGlerror = cbData.glError;
}
glPixelStorei(GL_UNPACK_ALIGNMENT, previousUnpackAlignment);
}
{
pfGlGenerateMipmap(target);
}
*pTarget = target;
if (pTexture) {
*pTexture = texname;
}
} else if (!texnameUser) {
glDeleteTextures(1, &texname);
}
return result;
}
GLenum* pGlerror,
unsigned int* pKvdLen, unsigned char** ppKvd)
{
if (ppKvd != NULL && pKvdLen == NULL)
result = ktxTexture_CreateFromStdioStream(file,
&texture);
return result;
result = ktxTexture_GLUpload(texture, pTexture, pTarget, pGlerror);
if (ppKvd != NULL) {
}
if (pDimensions) {
}
if (pIsMipmapped) {
*pIsMipmapped = GL_TRUE;
else
*pIsMipmapped = GL_FALSE;
}
}
ktxTexture_Destroy(texture);
return result;
}
ktxLoadTextureN(
const char*
const filename, GLuint* pTexture, GLenum* pTarget,
GLenum* pGlerror,
unsigned int* pKvdLen, unsigned char** ppKvd)
{
FILE* file = fopen(filename, "rb");
if (file) {
pIsMipmapped, pGlerror, pKvdLen, ppKvd);
fclose(file);
} else
return result;
}
GLboolean* pIsMipmapped, GLenum* pGlerror,
unsigned int* pKvdLen, unsigned char** ppKvd)
{
if (ppKvd != NULL && pKvdLen == NULL)
result = ktxTexture_CreateFromMemory(bytes, size,
&texture);
return result;
result = ktxTexture_GLUpload(texture, pTexture, pTarget, pGlerror);
if (ppKvd != NULL) {
}
if (pDimensions) {
}
if (pIsMipmapped) {
*pIsMipmapped = GL_TRUE;
else
*pIsMipmapped = GL_FALSE;
}
}
ktxTexture_Destroy(texture);
return result;
}