Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development

Reply
New Developer
ashutoshp
Posts: 9
Registered: ‎01-06-2014
My Device: Q10
Accepted Solution

Basic openGL 2.0 code with cascades

hi devs,

I am new to BB 10 development and also in C++.

Can anyone help me in setting up openGL 2.0 code with cascades (with either overlay or underlay). In the documentation the samples are either in openGL 1.1 with cascades or Core with 2.0. I just need a basic hello triangle kind of a sample.

 

Thanks

BlackBerry Development Advisor
smcveigh
Posts: 668
Registered: ‎11-29-2011
My Device: developer

Re: Basic openGL 2.0 code with cascades

I used to have a quick sample to do this before a disk crashed.. I'll see if I can rebuild it.  I don't think it was too difficult.

 

Feel free to have a go at it in the meantime yourself... Just take the usual helloworld type sample and first get it to create the opengl context in a new window instead of full-screen.  Then you can just park that window in a cascades ForeignWindowControl.

 

BlackBerry Development Advisor
RSperanza
Posts: 142
Registered: ‎03-08-2012
My Device: Z10

Re: Basic openGL 2.0 code with cascades

Hi.

 

I wrote the existing Cascades / OpenGL samples on GitHub.  All of the current samples (GoodCitizenCascades, Photo3D, and Stereoscopic3D) will be updated soon to use a new open source library I have been developing called libviews and their 3D code will be updated to add equivalent code using GL ES 2 (I wrote them originally in GL ES 1.1 because that was what I was most familiar with at the time).  The library should be available in early to mid February on GitHub.  One of my colleagues actually contacted me about a similar request so I am assume he may have been referring to this post.

 

I could potentially patch the current sample to add in GLES 2 code sooner but the new library handles GL ES 2 support better than the current code does so if you can wait until GoodCitizenCascades is updated, I think you will appreciate how much easier it is to use the new library.

 

If the timeline is an issue, let me know.  Thanks.

New Developer
ashutoshp
Posts: 9
Registered: ‎01-06-2014
My Device: Q10

Re: Basic openGL 2.0 code with cascades

Thanks smcveigh for the advice. I have already started to combine the cascades opengl 1.1 code with core openGL 2.0 template code. I was able to successfully compile the fragment and shader code using the openGL 2.0 template sample code. However, I am not able to see any object on the screen. All my openGL commands were successfully executed. Below is the snippet of the code. Can you quickly check if you can find any flaw in the code

 

void ApplicationUI::initForeignWindow()
{
	 foreignWindow = navPane->findChild<ForeignWindowControl*>("myForeignWindow");
	 QString mainWindowGroupId = Application::instance()->mainWindow()->groupId();
	 //AbsoluteLayoutProperties *layoutProperties = dynamic_cast<AbsoluteLayoutProperties*>(foreignWindow->layoutProperties());

	 if (screen_create_context(&mScreenCtx, SCREEN_APPLICATION_CONTEXT) != 0) {
	        fprintf(stderr,"Error while creating context\n");
	 }
	 else{
	        	fprintf(stderr,"Context created\n");
	 }

	 // Create a child window of the current window group, join the window group and set
	     // a window ID.
	 if (screen_create_window_type(&mScreenWindow, mScreenCtx, SCREEN_CHILD_WINDOW) != 0) {
		 fprintf(stderr,"Error while creating window type\n");
	 }
	 else {
	     fprintf(stderr,"Window created\n");
	 }

	 QByteArray groupArr = Application::instance()->mainWindow()->groupId().toAscii();

	 if (screen_join_window_group(mScreenWindow, groupArr.constData()) != 0) {
		 fprintf(stderr,"Window joining failed\n");
	 }
	 else
	 {
		 fprintf(stderr,"Window joining passed\n");
	 }

	QString windowId =  "HelloForeignWindowAppID";

	QByteArray idArr = windowId.toAscii();

	if (screen_set_window_property_cv(mScreenWindow, SCREEN_PROPERTY_ID_STRING, idArr.length(),idArr.constData()) != 0) {
		fprintf(stderr,"Window property not set\n");
	}
	else{
		fprintf(stderr,"Window property set\n");
	}

	EGLDisplay egl_disp;

	egl_disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);

	eglInitialize(egl_disp, NULL, NULL);

	if (eglBindAPI(EGL_OPENGL_ES_API) != EGL_TRUE){
		fprintf(stderr,"egl API not binded\n");
	}else{
		fprintf(stderr,"egl API binded successfully\n");
	}

	EGLint attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };

	EGLint attrib_list[]= { EGL_RED_SIZE,        8,
	                            EGL_GREEN_SIZE,      8,
	                            EGL_BLUE_SIZE,       8,
	                            EGL_DEPTH_SIZE,      16,
	                            EGL_SURFACE_TYPE,    EGL_WINDOW_BIT,
	                            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
	                            EGL_NONE};

	int num_configs;

	EGLConfig egl_conf;

	if(!eglChooseConfig(egl_disp, attrib_list, &egl_conf, 1, &num_configs)) {
		fprintf(stderr,"Error in egl choose config\n");
    }
	else{
		fprintf(stderr,"Choose config success\n");
	}



	EGLContext egl_ctx = eglCreateContext(egl_disp, egl_conf, EGL_NO_CONTEXT, attributes);

    if (egl_ctx == EGL_NO_CONTEXT) {
    	fprintf(stderr,"EGL not initialized\n");
    }
    else{
    	fprintf(stderr,"EGL initialized\n");
    }

//    int numberDisplays;
//
//    screen_get_context_property_iv(mScreenCtx, SCREEN_PROPERTY_DISPLAY_COUNT, &numberDisplays);

    if (screen_create_window(&mScreenWindow, mScreenCtx)){
    	fprintf(stderr,"Error while creating screen window");
    }
    else{
    	fprintf(stderr,"Screen Window created\n");
    }


//    if (screen_create_window_group(mScreenWindow,mainWindowGroupId)){
//    	fprintf(stderr,"screen window group created");
//    }else{
//    	fprintf(stderr,"Error while creating screen window group");
//    }


    int format = SCREEN_FORMAT_RGBX8888;

    if (screen_set_window_property_iv(mScreenWindow, SCREEN_PROPERTY_FORMAT, &format)){
    	fprintf(stderr,"Window property iv for format not set\n");
    }
    else{
    	fprintf(stderr,"Window property iv for format set\n");
    }

    int usage = SCREEN_USAGE_OPENGL_ES2 | SCREEN_USAGE_ROTATION;

    if (screen_set_window_property_iv(mScreenWindow, SCREEN_PROPERTY_USAGE, &usage)){
        	fprintf(stderr,"Window property iv for usage not set\n");
	}
	else{
		fprintf(stderr,"Window property iv for usage set\n");
	}

    screen_display_t screen_disp;

    if (screen_get_window_property_pv(mScreenWindow, SCREEN_PROPERTY_DISPLAY, (void **)&screen_disp)){
        fprintf(stderr, "Error while getting window property");
    }
    else{
    	fprintf(stderr, "Getting window property done\n");
    }

    screen_display_mode_t screen_mode;

    if (screen_get_display_property_pv(screen_disp, SCREEN_PROPERTY_MODE, (void**)&screen_mode)){
		fprintf(stderr, "Error while getting display window property\n");
	}
	else{
		fprintf(stderr, "Getting window display property done\n");
	}


    int size[1];
	if (screen_get_window_property_iv(mScreenWindow, SCREEN_PROPERTY_BUFFER_SIZE, size)){
		fprintf(stderr, "Error while getting screen property buffer\n");
	}
	else{
		fprintf(stderr, "getting screen property buffer done\n");
	}

	int buffer_size[1] = {size[0]};

    buffer_size[1] = size[0];
    buffer_size[0] = size[1];

    if (screen_set_window_property_iv(mScreenWindow, SCREEN_PROPERTY_BUFFER_SIZE, buffer_size)){
    	fprintf(stderr, "Error while setting screen property buffer\n");
    }
    else{
    	fprintf(stderr, "Setting screen property buffer done\n");
    }

    if (screen_create_window_buffers(mScreenWindow, 2)){
    	fprintf(stderr, "Error while creating window buffer\n");
    }
     else{
       	fprintf(stderr, "Window buffer created\n");
    }

    EGLSurface egl_surf = eglCreateWindowSurface(egl_disp, egl_conf, mScreenWindow, NULL);

    if (egl_surf == EGL_NO_SURFACE) {
    	fprintf(stderr,"Window surface not created\n");
	}
	else{
		fprintf(stderr,"Window surface created\n");
	}

    if (eglMakeCurrent(egl_disp, egl_surf, egl_surf, egl_ctx)!= EGL_TRUE){
    	fprintf(stderr,"Setting current surface failed\n");
    }
    else{
    	fprintf(stderr,"Current surface set\n");
    }

    if (eglSwapInterval(egl_disp, 1)!=EGL_TRUE){
    	fprintf(stderr,"Swap interval failed\n");
    }
    else{
    	fprintf(stderr,"Swap Interval OK\n");
    }

    EGLint surface_width, surface_height;

    eglQuerySurface(egl_disp, egl_surf, EGL_WIDTH, &surface_width);
    eglQuerySurface(egl_disp, egl_surf, EGL_HEIGHT, &surface_height);

    fprintf(stderr,"Surface width is %d and height is %d\n",surface_width,surface_height);

    if (screen_join_window_group(mScreenWindow, groupArr)){
    	fprintf(stderr,"join window group failed\n");
	}
	else{
		fprintf(stderr,"join window group passed\n");
	}

    if (screen_set_window_property_cv(mScreenWindow, SCREEN_PROPERTY_ID_STRING, windowId.toAscii().length(), windowId.toAscii())){
    	fprintf(stderr,"Set screen window id failed\n");
	}
	else{
		fprintf(stderr,"Set screen window id passed\n");
	}

    //Start creating objects



    GLfloat vertices[8];
    GLfloat colors[16];

    //Initialize vertex and color data
        vertices[0] = -0.25f;
        vertices[1] = -0.25f;

        vertices[2] = 0.25f;
        vertices[3] = -0.25f;

        vertices[4] = -0.25f;
        vertices[5] = 0.25f;

        vertices[6] = 0.25f;
        vertices[7] = 0.25f;

        colors[0] = 1.0f;
        colors[1] = 0.0f;
        colors[2] = 1.0f;
        colors[3] = 1.0f;

        colors[4] = 1.0f;
        colors[5] = 1.0f;
        colors[6] = 0.0f;
        colors[7] = 1.0f;

        colors[8] = 0.0f;
        colors[9] = 1.0f;
        colors[10] = 1.0f;
        colors[11] = 1.0f;

        colors[12] = 0.0f;
        colors[13] = 1.0f;
        colors[14] = 1.0f;
        colors[15] = 1.0f;


        const char* vSource =
                    "precision mediump float;"
                    "uniform mat4 u_projection;"
                    "uniform mat4 u_transform;"
                    "attribute vec4 a_position;"
                    "attribute vec4 a_color;"
                    "varying vec4 v_color;"
                    "void main()"
                    "{"
                    "    gl_Position = u_projection * u_transform * a_position;"
                    "    v_color = a_color;"
                    "}";

            const char* fSource =
                    "varying lowp vec4 v_color;"
                    "void main()"
                    "{"
                    "    gl_FragColor = v_color;"
                    "}";


            GLint status;

            // Compile the vertex shader
                GLuint vs = glCreateShader(GL_VERTEX_SHADER);
                if (!vs) {
                    fprintf(stderr, "Failed to create vertex shader: %d\n", glGetError());
                } else {
                	fprintf(stderr, "create vertex shader passed\n");
                    glShaderSource(vs, 1, &vSource, 0);
                    glCompileShader(vs);
                    glGetShaderiv(vs, GL_COMPILE_STATUS, &status);
                    if (GL_FALSE == status) {
                        GLchar log[256];
                        glGetShaderInfoLog(vs, 256, NULL, log);

                        fprintf(stderr, "Failed to compile vertex shader: %s\n", log);

                        glDeleteShader(vs);
                    }
                }

                // Compile the fragment shader
                GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
                if (!fs) {
                    fprintf(stderr, "Failed to create fragment shader: %d\n", glGetError());
                } else {
                	fprintf(stderr, "Create fragment shader passed\n");
                    glShaderSource(fs, 1, &fSource, 0);
                    glCompileShader(fs);
                    glGetShaderiv(fs, GL_COMPILE_STATUS, &status);
                    if (GL_FALSE == status) {
                        GLchar log[256];
                        glGetShaderInfoLog(fs, 256, NULL, log);

                        fprintf(stderr, "Failed to compile fragment shader: %s\n", log);

                        glDeleteShader(vs);
                        glDeleteShader(fs);
                    }
                }

                GLuint program;

                // Create and link the program
				program = glCreateProgram();
				if (program)
				{
					fprintf(stderr, "shader program passed\n");
					glAttachShader(program, vs);
					glAttachShader(program, fs);
					glLinkProgram(program);

					glGetProgramiv(program, GL_LINK_STATUS, &status);
					if (status == GL_FALSE)    {
						GLchar log[256];
						glGetProgramInfoLog(fs, 256, NULL, log);

						fprintf(stderr, "Failed to link shader program: %s\n", log);

						glDeleteProgram(program);
						program = 0;

					} else
					{
						fprintf(stderr, "Link shader program passed\n");
					}
				} else {
					fprintf(stderr, "Failed to create a shader program\n");

					glDeleteShader(vs);
					glDeleteShader(fs);

				}

				glUseProgram(program);

				GLuint projectionLoc = glGetUniformLocation(program, "u_projection");
				    {
				        GLfloat left = 0.0f;
				        GLfloat right = (float)(surface_width) / (float)(surface_height);
				        GLfloat bottom = 0.0f;
				        GLfloat top = 1.0f;
				        GLfloat zNear = -1.0f;
				        GLfloat zFar = 1.0f;
				        GLfloat ortho[16] = {2.0 / (right-left), 0, 0, 0,
				                            0, 2.0 / (top-bottom), 0, 0,
				                            0, 0, -2.0 / (zFar - zNear), 0,
				                            -(right+left)/(right-left), -(top+bottom)/(top-bottom), -(zFar+zNear)/(zFar-zNear), 1};
				        glUniformMatrix4fv(projectionLoc, 1, false, ortho);
				    }


				    GLuint transformLoc;
				    GLuint positionLoc;
				    GLuint colorLoc;

				    // Store the locations of the shader variables we need later
					transformLoc = glGetUniformLocation(program, "u_transform");
					positionLoc = glGetAttribLocation(program, "a_position");
					colorLoc = glGetAttribLocation(program, "a_color");

					// We don't need the shaders anymore - the program is enough
					glDeleteShader(fs);
					glDeleteShader(vs);

					GLuint vertexID;
					GLuint colorID;

					// Generate vertex and color buffers and fill with data
					glGenBuffers(1, &vertexID);
					glBindBuffer(GL_ARRAY_BUFFER, vertexID);
					glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

					glGenBuffers(1, &colorID);
					glBindBuffer(GL_ARRAY_BUFFER, colorID);
					glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);

					static GLfloat matrix[16] = {1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1};

					// Perform the same translation as the GLES1 version
					matrix[12] = (float)(surface_width) / (float)(surface_height) / 2;
					matrix[13] = 0.5;
					glUniformMatrix4fv(transformLoc, 1, false, matrix);

					fprintf(stderr,"OpenGL initialized");


					// Render

					// Increment the angle by 0.5 degrees
					//static float angle = 0.0f;
					//angle += 0.5f * M_PI / 180.0f;
					float angle = 30 * M_PI / 180.0f;

					//Typical render pass
					glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

					glClearDepthf(1.0f);
					glClearColor(1.0f,0.0f,0.0f,1.0f);

					glEnable(GL_CULL_FACE);

					// Enable and bind the vertex information
					glEnableVertexAttribArray(positionLoc);
					glBindBuffer(GL_ARRAY_BUFFER, vertexID);
					glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);

					// Enable and bind the color information
					glEnableVertexAttribArray(colorLoc);
					glBindBuffer(GL_ARRAY_BUFFER, colorID);
					glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);

					// Effectively apply a rotation of angle about the y-axis.
					matrix[0] = cos(angle);
					matrix[2] = -sin(angle);
					matrix[8] = sin(angle);
					matrix[10] = cos(angle);
					glUniformMatrix4fv(transformLoc, 1, false, matrix);

					// Same draw call as in GLES1.
					glDrawArrays(GL_TRIANGLE_STRIP, 0 , 4);

					// Disable attribute arrays
					glDisableVertexAttribArray(positionLoc);
					glDisableVertexAttribArray(colorLoc);

				    int rc = eglSwapBuffers(egl_disp, egl_surf);
				    if (rc != EGL_TRUE) {
				       fprintf(stderr,"Swap buffer failed\n");
				    }else{
				    	fprintf(stderr,"Swap buffer passed\n");
				    }


}

 I call the above function from the application object constructor as below

ApplicationUI::ApplicationUI(bb::cascades::Application *app) :
        QObject(app)
{


    // Create scene document from main.qml asset, the parent is set
    // to ensure the document gets destroyed properly at shut down.
    QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(this);

    if (!qml->hasErrors()) {
//            OpenGLView::setRenderingAPI(GL_ES_2);

            // The application NavigationPane is created from QML.
            // The application NavigationPane is created from QML.
            navPane = qml->createRootObject<NavigationPane>();
            if (navPane) {
            	fprintf(stderr,"navigation pane found\n");
                // Finally the main scene for the application is set the Page.
            	 Application::instance()->setScene(navPane);
                initForeignWindow();
            }
            else{
            	fprintf(stderr,"navigation pane not found\n");
            }

        }





}

 

Any kind of help appreciated.

Thanks

 

New Developer
ashutoshp
Posts: 9
Registered: ‎01-06-2014
My Device: Q10

Re: Basic openGL 2.0 code with cascades

hi RSperenza,

Good to hear that you are developing a open source library. Well unfortunately time is a constraint for me and hence I need to continue with openGL 2.0 cascades for now. I was actually just looking for a sample Hello triangle kind of a code in openGL 2.0 with cascades and not any heavy code example. I have posted a sample code in my previous post and was successfully able to compile fragment and shader code in the same. I have picked all the vertices and other sample code from the opengl 2.0 core template but still not able to view any object on th screen. If you can quickly find out what I am doing wrong, it will be really helpful for me.

 

Thanks again for your advice.

BlackBerry Development Advisor
RSperanza
Posts: 142
Registered: ‎03-08-2012
My Device: Z10

Re: Basic openGL 2.0 code with cascades

Fair enough.  That's why I asked about the timeline.

 

I looked at your code and everything appears to be in order.  Assuming it is correct, one possibility is that the winding order of your trangle strip vertices is the reverse of what it should be to avoid being culled.  Try commenting out the glEnable command for culling and see if it appears.  If so, reverse the order of the vertices and see if that helps after re-enabling the option.

 

I also had similar problems when I didn't link the attributes properly to the input data.  In my 2D code that I am currently finishing off, I didn't bind my arrays to buffers.  I linked vertices to the texture as follows:


    glEnableVertexAttribArray(positionLoc);
    glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, _renderVertexCoords);

It seems to work well for me.  I believe your calls with the last parameter as 0 are supposed to work as well when you do use buffers but something is not quite right if you don't see anything.  From what I read, seeing no rendering is an indication of a silent failure in the rendering pipeline.

 

Let me know if the above suggestions help or if you continue to encounter difficulties.

 

New Developer
ashutoshp
Posts: 9
Registered: ‎01-06-2014
My Device: Q10

Re: Basic openGL 2.0 code with cascades

Thanks for your suggestion RSperanza. Commenting the Cull face did not work . However, I just realized that even the glClearColor(0.0f,1.0f,0.0f,1.0f) command is not changing my background color. It always shows black when I should see green in this case. I feel there is some problem setting up the openGL window. I do not know what as of now.

New Developer
ashutoshp
Posts: 9
Registered: ‎01-06-2014
My Device: Q10

Re: Basic openGL 2.0 code with cascades

OK I cracked it! I had to comment out the below opengl function to make it work.  So either use screen_create_window or screen_create_window_type or screen_create_window_type_pv depending upon the display. This is my guess. Thanks guys for your support. Now the real development starts!

 

if (screen_create_window(&mScreenWindow, mScreenCtx)){
    	fprintf(stderr,"Error while creating screen window");
    }
    else{
    	fprintf(stderr,"Screen Window created\n");
    }

 

BlackBerry Development Advisor
RSperanza
Posts: 142
Registered: ‎03-08-2012
My Device: Z10

Re: Basic openGL 2.0 code with cascades

Good to hear.

 

Whenever you mix native windows with Cascades, the native windows should always be child windows and should share the same window group as the Cascades window.   If you look at my sample code in either GoodCitizenCascades or Stereoscopic3D, OpenGLView.cpp and OpenGLThread.cpp have most of the boilerplate code for creating the windows properly (the versions in Stereoscopic3D are newer and can be copied into the other sample if you downloaded both).   The app classes also show you how to obtain the group ID from the main Cascades window. 

 

God luck with the rest of the app and feel free to contact me or post more questions in this forum if you run into any more issues.

New Developer
ashutoshp
Posts: 9
Registered: ‎01-06-2014
My Device: Q10

Re: Basic openGL 2.0 code with cascades

Thanks.