I've modified NVIDIA's SDK sample ( which looks like it was the basis for Ogre's sample ) and that seems to work OK.
Code: Select all
//
// simple texture array example
//
// Demonstrates the use of EXT_texure_array.
//
// Author: Simon Green
// Email: sdkfeedback@nvidia.com
//
// Copyright (c) NVIDIA Corporation. All rights reserved.
////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <map>
#include <GL/glew.h>
#include <GL/glut.h>
#include <nvImage.h>
#include <nvGlutManipulators.h>
#define NV_REPORT_COMPILE_ERRORS
#include <nvShaderUtils.h>
using std::map;
////////////////////////////////////////////////////////////////////////////////
//
// Globals
//
////////////////////////////////////////////////////////////////////////////////
// change #1, path adjusted to run from the IDE
//#define IMAGE_PATH "../media/textures/"
#define IMAGE_PATH "../../media/textures/"
nv::GlutExamine manipulator;
GLuint fprog, lerp_fprog;
enum UIOption {
OPTION_DISPLAY_WIREFRAME,
OPTION_LERP_LAYERS,
OPTION_ANIMATE,
OPTION_USE_PROGRAM,
OPTION_COUNT
};
bool options[OPTION_COUNT];
map<char,UIOption> optionKeyMap;
//
// fragment program to look up in texture array
//
static const char *fprog_code =
"!!NVfp4.0 \n"
"TEMP texcoord; \n"
"MOV texcoord, fragment.texcoord[0]; \n"
"FLR texcoord.z, texcoord; \n"
"TEX result.color, texcoord, texture[0], ARRAY2D; \n"
"END";
//
// interpolate between two nearest layers in array
//
static const char *lerp_fprog_code =
"!!NVfp4.0 \n"
"TEMP texcoord, c0, c1, frac; \n"
"MOV texcoord, fragment.texcoord[0]; \n"
"FLR texcoord.z, texcoord; \n"
"TEX c0, texcoord, texture[0], ARRAY2D; \n"
"ADD texcoord.z, texcoord, { 0, 0, 1, 0 }; \n"
"TEX c1, texcoord, texture[0], ARRAY2D; \n"
"FRC frac.x, fragment.texcoord[0].z; \n"
"LRP result.color, frac.x, c1, c0; \n"
"END";
////////////////////////////////////////////////////////////////////////////////
//
// Functions
//
////////////////////////////////////////////////////////////////////////////////
//
//
//////////////////////////////////////////////////////////////////////
void init_opengl() {
glEnable(GL_DEPTH_TEST);
glClearColor(0.2, 0.2, 0.2, 1.0);
glewInit();
if (!glewIsSupported(
"GL_VERSION_2_0 "
"GL_ARB_vertex_program "
"GL_ARB_fragment_program "
"GL_EXT_texture_array "
"GL_NV_gpu_program4 " // also initializes NV_fragment_program4 etc.
))
{
printf("Unable to load extension(s), this sample requires:\n OpenGL version 2.0\n"
" GL_ARB_vertex_program\n GL_ARB_fragment_program\n GL_EXT_texture_array\n"
" GL_NV_gpu_program4\n Exiting...\n");
exit(-1);
}
// load images
#define NIMAGES 4
// change #2, use dds (dxt5) images
char *imageName[] = {
//IMAGE_PATH "rock.png",
//IMAGE_PATH "snow.png",
//IMAGE_PATH "grass.png",
//IMAGE_PATH "graydirt.png"
IMAGE_PATH "rock.dds",
IMAGE_PATH "snow.dds",
IMAGE_PATH "grass.dds",
IMAGE_PATH "graydirt.dds"
};
nv::Image images[NIMAGES];
for(int i=0; i<NIMAGES; i++) {
images[i].loadImageFromFile( imageName[i]);
}
// load images as 2d texture array
GLuint texid;
glGenTextures(1, &texid);
glBindTexture( GL_TEXTURE_2D_ARRAY_EXT, texid);
glTexParameteri( GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri( GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri( GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri( GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri( GL_TEXTURE_2D_ARRAY_EXT, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
// change #3, allocate some storage
char *tmp = new char[512*512*4];
// 2D Texture arrays a loaded just like 3D textures
// change #4, use glCompressedTexImage3D instead of glTexImage3D
//glTexImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0, GL_RGBA8, images[0].getWidth(), images[0].getHeight(), NIMAGES, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, images[0].getWidth(), images[0].getHeight(), NIMAGES, 0, 512*512*4, tmp);
for (int i = 0; i < NIMAGES; i++) {
// change #5, use glCompressedTexSubImage instead of glTexSubImage
//glTexSubImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, 0, 0, i, images[i].getWidth(), images[i].getHeight(), 1, images[i].getFormat(), images[i].getType(), images[i].getLevel(0));
glCompressedTexSubImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, 0, 0, i, images[i].getWidth(), images[i].getHeight(), 1, images[i].getFormat(), images[i].getImageSize(), images[i].getLevel(0));
}
fprog = nv::CompileASMShader(GL_FRAGMENT_PROGRAM_ARB, fprog_code);
lerp_fprog = nv::CompileASMShader(GL_FRAGMENT_PROGRAM_ARB, lerp_fprog_code);
}
//
//
//////////////////////////////////////////////////////////////////////
void draw_quad() {
// r texture coordinate is used to select layer
glBegin(GL_QUADS);
glTexCoord3f(0.0, 0.0, 0.0);
glVertex2f(-1.0, -1.0);
glTexCoord3f(1.0, 0.0, 4.0);
glVertex2f(1.0, -1.0);
glTexCoord3f(1.0, 1.0, 4.0);
glVertex2f(1.0, 1.0);
glTexCoord3f(0.0, 1.0, 0.0);
glVertex2f(-1.0, 1.0);
glEnd();
}
//
//
//////////////////////////////////////////////////////////////////////
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
manipulator.applyTransform();
glColor3f(1.0, 1.0, 1.0);
if ( options[OPTION_LERP_LAYERS]) {
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, lerp_fprog);
} else {
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, fprog);
}
if (options[OPTION_USE_PROGRAM]) {
glEnable(GL_FRAGMENT_PROGRAM_ARB);
}
glPolygonMode( GL_FRONT_AND_BACK, options[OPTION_DISPLAY_WIREFRAME] ? GL_LINE : GL_FILL);
draw_quad();
glDisable(GL_FRAGMENT_PROGRAM_ARB);
glutSwapBuffers();
}
//
//
//////////////////////////////////////////////////////////////////////
void idle() {
if ( options[OPTION_ANIMATE])
manipulator.idle();
glutPostRedisplay();
}
//
//
//////////////////////////////////////////////////////////////////////
void key(unsigned char k, int x, int y) {
k = tolower(k);
if (optionKeyMap.find(k) != optionKeyMap.end())
options[optionKeyMap[k]] = !options[optionKeyMap[k]];
switch(k) {
case 27:
case 'q':
exit(0);
break;
}
glutPostRedisplay();
}
//
//
//////////////////////////////////////////////////////////////////////
void resize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)w/(GLfloat)h, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
manipulator.reshape(w, h);
}
//
//
//////////////////////////////////////////////////////////////////////
void mouse(int button, int state, int x, int y) {
manipulator.mouse(button, state, x, y);
}
//
//
//////////////////////////////////////////////////////////////////////
void motion(int x, int y) {
manipulator.motion(x, y);
}
//
//
//////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitWindowSize(512, 512);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB);
glutCreateWindow("simple_texture_array");
init_opengl();
manipulator.setDollyActivate( GLUT_LEFT_BUTTON, GLUT_ACTIVE_CTRL);
manipulator.setPanActivate( GLUT_LEFT_BUTTON, GLUT_ACTIVE_SHIFT);
manipulator.setDollyPosition( -2.0f);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutIdleFunc(idle);
glutKeyboardFunc(key);
glutReshapeFunc(resize);
//configure the options
optionKeyMap['w'] = OPTION_DISPLAY_WIREFRAME;
options[OPTION_DISPLAY_WIREFRAME] = false;
optionKeyMap['f'] = OPTION_USE_PROGRAM;
options[OPTION_USE_PROGRAM] = true;
optionKeyMap[' '] = OPTION_ANIMATE;
options[OPTION_ANIMATE] = true;
optionKeyMap['l'] = OPTION_LERP_LAYERS;
options[OPTION_LERP_LAYERS] = false;
//print the help info
printf( "Simple_texture_array - sample showing the usage of texture arrays\n");
printf( " Commands:\n");
printf( " q / [ESC] - Quit the application\n");
printf( " [SPACE] - Toggle continuous animation\n");
printf( " f - Toggle using a fragment program\n");
printf( " w - Toggle displaying wireframe\n");
printf( " l - Toggle interpolation between texture layers\n\n");
glutMainLoop();
return 0;
}
I've also modified PixelBox::getSubVolume to return what appear to be correct values for a DXT5 texture, and Ogre's sample now at least runs.
But all I can see from the shader is the texture from the first layer.
The obvious difference between the two is glCompressedTexSubImage3D vs PixelUtil::bulkPixelConversion.