Page 1 of 2

C++ OpenGL to Irrlicht (Using OpenGL functions in irrlicht)

Posted: Fri May 14, 2010 1:19 pm
by LosNir
Hi. I'm trying to port a pure written OpenGL Shader Program (not .glsl files!) to pure irrlicht functions.

How do I access OpenGL functions like "glCreateShader" or "glUniform1f" in irrlicht? Something like:

Code: Select all

ClassToHandleShaders* useSahders = new ClassToHandleShaders();
useShaders->createShader(X, Y, Z);
And this will automatically call the currently used driver pure functions (When using OpenGL it will call glCreateShader, and in d3d it will call it's equivalent).

I saw these functions implemented in "COpenGLSLMaterialRenderer.cpp" and some other files, but I can't seem to figure out where they are being used in irrlicht.

Thanks!

Posted: Fri May 14, 2010 1:21 pm
by ent1ty

Posted: Fri May 14, 2010 1:23 pm
by hybrid
Just read example 10, all those internal functions are called automatically for you when creating a shader based material.

Posted: Fri May 14, 2010 1:38 pm
by LosNir
Yeah I know that, that's what Irrlicht is for. But I have some tons of OpenGL functions and I don't know which is which. Which is done by function X of irrlicht and which is done by function Y of irrlicht.

I have this code for exmaple:

Code: Select all

Program::Program(int files, char** fileNames, char *options) {
    program = -1;
    vertexShader = -1;
    fragmentShader = -1;
    geometryShader = -1;

    const char **contents = (const char**) malloc((files + 2) * sizeof(char*));

    int i;
    bool geo = false;
    for (i = 0; i < files; ++i) {
        contents[i + 2] = textFileRead(fileNames[i]);
        if (strstr(contents[i + 2], "_GEOMETRY_") != NULL) {
            geo = true;
        }
    }

    printf("LOADING %s\n", fileNames[files - 1]);

    if (program == -1) {
        program = glCreateProgram();
        vertexShader = glCreateShader(GL_VERTEX_SHADER);
        fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
        glAttachShader(program, vertexShader);
        glAttachShader(program, fragmentShader);
        assert(glGetError() == 0);
    }

    contents[0] = "#define _VERTEX_\n";
    contents[1] = options == NULL ? "" : options;
    glShaderSource(vertexShader, files + 2, contents, NULL);
    glCompileShader(vertexShader);
    checkShader(vertexShader);
    assert(glGetError() == 0);

    if (geo) {
        geometryShader = glCreateShader(GL_GEOMETRY_SHADER_EXT);
        glAttachShader(program, geometryShader);
        contents[0] = "#define _GEOMETRY_\n";
        contents[1] = options == NULL ? "" : options;
        glShaderSource(geometryShader, files + 2, contents, NULL);
        glCompileShader(geometryShader);
        printShaderLog(geometryShader);
        glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT, GL_TRIANGLES);
        glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, GL_TRIANGLE_STRIP);
        glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT, 3 * 5);
    }

    contents[0] = "#define _FRAGMENT_\n";
    glShaderSource(fragmentShader, files + 2, contents, NULL);
    glCompileShader(fragmentShader);
    checkShader(fragmentShader);
    assert(glGetError() == 0);

    for (i = 0; i < files; ++i) {
        free((void*) contents[i + 2]);
    }

    glBindAttribLocation(program, 1, "normal");
    glBindAttribLocation(program, 2, "color");

    glLinkProgram(program);
    GLint logLength;
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        char *log = new char[logLength];
        glGetProgramInfoLog(program, logLength, &logLength, log);
        printf("%s", log);
    }

    if (checkProgram(program)) {
        assert(glGetError() == 0);
    } else {
        printShaderLog(vertexShader);
        printShaderLog(fragmentShader);
        exit(-1);
    }
}
What could be the Irrlicht equivalent, that's my question actually.
Of course I don't expect anyone to convert this code, I'm just showing what I'm dealing with.

Posted: Fri May 14, 2010 5:59 pm
by hybrid
You have to create all three input shaders at once, and pass them to the Irrlicht function. The geometry shader parameters can be passed there as well. AttribLocation is fixed, so adapt to the vertex structure you are using.

Posted: Fri May 14, 2010 9:12 pm
by LosNir
I've made some more reading.
The "Irrlicht function" you are talking about is addHighLevelShaderMaterial / FromFiles.. right?

I've taken another look at the code, and it seems it loads the shader files, adds some #define lines and adds the options passed.
If you take a look at the code, assuming it's being called like:

Code: Select all

    char* files[2];
    char options[512];
    files[0] = "Resources/shaders/water/atmosphere.glsl";
    files[1] = "Resources/shaders/water/ocean.glsl";
    sprintf(options, "#define %sSEA_CONTRIB\n#define %sSUN_CONTRIB\n#define %sSKY_CONTRIB\n#define %sCLOUDS\n#define %sHARDWARE_ANISTROPIC_FILTERING\n",
        seaContrib ? "" : "NO_", sunContrib ? "" : "NO_", skyContrib ? "" : "NO_", cloudLayer ? "" : "NO_", manualFilter ? "NO_" : "");

render = new Program(2, files, options);
Variable `contents` is a 4 cell array, last 2 induces (2,3) holds the shader data read by `textFileRead`, and 2 first induces (0, 1) holds the options and the definitions of vertex / fragment.

With the above information, we can assume this:

1. Since Irrlicht call's `glCreateShader` and `glAttachShader` automatically when calling `addHighLevelShaderMaterial ` (we need that at the first if condition) we can "forget" them.

2. We know`glShaderSource` requires a char* array, which is parameter named "string" which contains the shader code it self. Here: http://www.opengl.org/sdk/docs/man/xhtm ... Source.xml

3. We know that `contents` is being passed to `glShaderSource` as parameter "string", and we also know that the size of `contents` (4) is being passed to parameter "length" which should be the size of parameter "string".

4. So everything is correct by now. However, in Irrlicht, parameter "count" is being hard-coded to 1 as in:

Code: Select all

Driver->extGlShaderSource(shaderHandle, 1, &shader, NULL);
From `COpenGLSLMaterialRenderer.cpp`.

This requires us to pass a 1-cell array to parameter "string", meaning I should merge `contents` to one (char*) variable, delimiting each cell from `contents` array with a line break. Right?

Could you elaborate more on "glBindAttribLocation"?

If I made some wrong assumptions please let me know! And sorry for that very-long-too-obvious-post, I just like to lay down information as it is in steps so it's easier to understand :)

Posted: Fri May 14, 2010 10:01 pm
by hybrid
Yes, you're right with your assumptions. The glBindAttribLocation defines the semantics of the structural elements of each vertex. Since Irrlicht does not use a flexible vertex format, the locations are predefined and are automatically defined. You just have to make sure that your shaders expect the data in those predefined locations.

Posted: Sat May 15, 2010 12:09 am
by LosNir
Alright. Before I continue, what is exactly the value returned from `addHighLevelShaderMaterial`? glCreateProgram?

Posted: Sat May 15, 2010 7:25 am
by hybrid
It's an internal ID, which should be used as a MaterialType when using this material.

Posted: Sat May 15, 2010 5:00 pm
by LosNir
I've made some progress. Some of the shaders are loaded successfully, but some giving me compile error:
[GUI Engine] Sucessfully loaded font 'fonts/arial12.bmp' as `defaultFont`!
Loading Shader.. ocean.glsl
Loading Shader.. sky.glsl
GLSL shader failed to compile

0(532) : error C1008: undefined variable "screenToCamera"

Loading Shader.. skymap.glsl
GLSL shader failed to compile

0(553) : error C1008: undefined variable "sunDir"
0(565) : error C1008: undefined variable "sunDir"

Loading Shader.. clouds.glsl
GLSL shader failed to compile

0(526) : error C1008: undefined variable "worldToScreen"
What could be the problem? Here is the code: http://codetrunk.com/f8b092a5

`loadRequiredShaders` is being called.

EDIT:

Got it working. It was a null termination problem that took forever to fix.

Posted: Sat May 15, 2010 8:24 pm
by LosNir
Another question, when calling "setPixelShaderConstant" on the ShaderConstantCallback, what value of count should I use for the following types?

sampler2D
sampler3D
float

Thanks.

Posted: Sat May 15, 2010 10:40 pm
by stefbuet
You put your texture on the model with node->setMaterialTexture(ID, myTexture);
where ID = 0, 1, 2, 3, .....

And in the setPixelShader constant, you just send the texture ID like this :

Code: Select all

int textureAddress=0;
        services->setPixelShaderConstant("mySample2D", (float*)(&textureAdress),1); 
Currentlly 3D texture are not supported by Irrlicht, BUT
thespecial1 managed to use them with shaders, maybe you should ask him some tips about it.

Posted: Sun May 16, 2010 12:04 am
by BlindSide
Yeah, make sure the texture id is stored in an INT and passed as a float pointer like stefbuet's example.

Posted: Sun May 16, 2010 4:57 am
by LosNir
Yup, for example I did:

Code: Select all

rServices->setPixelShaderConstant("skyIrradianceSampler", &this->m_irradianceUnit, 1);

Posted: Sun May 16, 2010 3:26 pm
by LosNir

Code: Select all

    float *data = new float[16*64*3];
    FILE *f = fopen("data/irradiance.raw", "rb");
    fread(data, 1, 16*64*3*sizeof(float), f);
    fclose(f);
    glActiveTexture(GL_TEXTURE0 + IRRADIANCE_UNIT);
    glGenTextures(1, &irradianceTex);
    glBindTexture(GL_TEXTURE_2D, irradianceTex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F_ARB, 64, 16, 0, GL_RGB, GL_FLOAT, data);
    delete[] data;
How can I turn this code into Irrlicht equivalent?

Code: Select all

this->waterSceneNode->setMaterialTexture(IRRADIANCE_UNIT, this->m_irrlichtDevice->getVideoDriver()->getTexture("data/irradiance.raw"));
Will this do the work?