theoden theoden - 3 months ago 21
C Question

OpenGL4 gl_texture_2d_array won't display

I want to get started with modern OpenGL while reading the superbible book by coding a cellular automata using a 2d-array texture of size 1280x1280x2 and computing the next state to another layer in a compute shader. The idea is impiously stolen from glumpy examples.

However, while having such ambition in mind, I got confused at even trying to display it, not even passing the samplers into shaders.

Below I included both, the generator, which works OK, and the piece of code that does contain a problem.

gen



#!/usr/bin/env perl

use strict;
use warnings;


sub get_arg {
return (scalar @ARGV == 0) ? shift : shift @ARGV;
}

my $size = get_arg 1280;
my $rate = get_arg ($size >> 1);

my $symbol = (sub { ((shift) < $rate) ? '*' : '_' } );

print "$size\n";
for (0..$size) {
print $symbol->(int(rand() * $size)) for (0..$size);
print "\n";
}


code



#include <stdio.h>
#include <stdbool.h>
#include <assert.h>


// including opengl libraries on linux/osx

//include glew
#include <GL/glew.h>

//include opengl
#if defined (__APPLE_CC__)
#include <OpenGL/gl3.h>
#else
#include <GL/gl3.h> /* assert OpenGL 3.2 core profile available. */
#endif

//include glfw3
#define GLFW_INCLUDE_GL3 /* don't drag in legacy GL headers. */
#define GLFW_NO_GLU /* don't drag in the old GLU lib - unless you must. */
#include <GLFW/glfw3.h>

// ----------- the program itself

GLFWwindow *g_window;

#define SIZE 1280
#define WIDTH SIZE
#define HEIGHT SIZE
#define DEPTH 2


init_glfw(const char *name) {
// start GL context and O/S window using the GLFW helper library
assert(glfwInit());

#if defined(__APPLE_CC__)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#endif
g_window = glfwCreateWindow(WIDTH, HEIGHT, name, NULL, NULL);
assert(g_window != NULL);
glfwMakeContextCurrent(g_window);

// start GLEW extension handler
glewExperimental = GL_TRUE;
glewInit();

// tell GL to only draw onto a pixel if the shape is closer to the viewer
glEnable(GL_DEPTH_TEST); // enable depth-testing
glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}


typedef enum { FILLED = '*', EMPTY = '_' } SYMBOL;
load_array(GLubyte array[SIZE * SIZE * DEPTH], FILE *stream) {
static char c;
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
bool approved = false;
GLubyte *it = &array[SIZE * i + j];
while(!approved) {
approved = true;
c = getc(stream);
assert(c != EOF);
switch(c) {
case FILLED:
*it = 0x00;
break;
case EMPTY:
*it = 0xff;
break;
default:
approved = false;
break;
}
}
assert(*it == 0x00 || *it == 0xff);
it[SIZE * SIZE] = it[0];
}
}
}


GLuint create_2d_texture() {
static GLuint texture = 0;
assert(texture == 0);

static GLubyte field[SIZE * SIZE << 1];
load_array(field, stdin);

glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_ALPHA8, SIZE, SIZE, DEPTH);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, SIZE, SIZE, DEPTH, GL_ALPHA, GL_UNSIGNED_BYTE, field);

glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);

return texture;
}


display() {
GLuint texture = create_2d_texture();
assert(texture != 0);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT_AND_BACK);

while(!glfwWindowShouldClose(g_window)) {
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
glPushMatrix();
glEnable(GL_TEXTURE_2D_ARRAY);
glBegin(GL_QUADS);
glTexCoord3s(0, SIZE, 0); glVertex3f( 0.0f, 0.0f, 0.0 );
glTexCoord3s(SIZE, SIZE, 0); glVertex3f( SIZE, 0.0f, 0.0 );
glTexCoord3s(0, SIZE, 0); glVertex3f( SIZE, SIZE, 0.0 );
glTexCoord3s(0, 0, 0); glVertex3f( 0.0f, SIZE, 0.0 );
glEnd();
glPopMatrix();

glfwSwapBuffers(g_window);
glfwPollEvents();
if(glfwGetKey(g_window, GLFW_KEY_ESCAPE)) {
glfwSetWindowShouldClose(g_window, 1);
}
}
}


main() {
init_glfw("I want to display a texture");
display();
glfwDestroyWindow(g_window);
glfwTerminate();
}


Could you help me to analyse the issues with displaying the 2d array on the screen, please? What I am trying to achieve is to make the whole window randomly black-and-white, but so far I ended up completely confused just adding more layers from googled solutions and man pages.

I am not asking for a working code, just a comprehensible explanation which would help me to get through this problem.

Answer
glEnable(GL_TEXTURE_2D_ARRAY);

That gave you an OpenGL error. Even in compatibility profiles, you cannot enable an array texture of any kind. Why?

Because you cannot used fixed-function processing with array textures at all. You cannot use glTexEnv to fetch from an array texture. They're wholly and completely shader-based constructs.

So if you want to use an array texture, you must use a shader.