Initialising & Using CPVRTPrint3D outside of the PVRShell

Hi there,



I’m trying to use the PVRSDK in my own ObjectiveC/C++ project, without using PVRShell.



I plan on using the SDK mainly for parsing POD/PFX files, but I thought I would try using CPVRTPrint3D as a test to see that I had the PVRSDK correctly integrated into my project.



I have a rendering class that is purely C++ that renders a test sphere independently of PVRSDK. I have been trying to add in a call to PVRPrint3D to display a simple “Hello World” message on my screen alongside my existing 3D output.



All the demos in the SDK seem to extend the PVRShell class. I’ve had a look at the demos anyway, but the only set up they seem to do is a call to the CPVRTPrint3D.SetTextures() method. This doesn’t seem enough setup to me, and indeed when I run my code I get a run-time error on the call to CPVRTPrint3D.Flush();



So I’m guessing if I’m using Print3D outside of the PVRShell I have more setup to do?



Could someone give me a few pointers on how I would go about configuring and calling CPVRTPrint3D from a Non-PVRShell based application?



Thanks in advance :slight_smile:



Andre.


Hi Andre.

Print3D is not coupled with PVRShell and should therefore work without it and you shouldn’t need to call any further functions, assuming the SetTextures() function returns PVR_SUCCESS.



Could you describe the crash in any more detail?

Hi Arron,



thanks for your fast response!



I am calling SetTextures from my SetViewPort method that is called after my buffers are created:




void RenderingEngine::SetViewPort(int x, int y, int width, int height)<br />
{<br />
float scale = 4.0f;<br />
float aspect = ((float)width / (float)height);<br />
<br />
float nh, nw;<br />
if (aspect >= 1.0) {<br />
nh = (1/aspect);<br />
nw = 1;<br />
} else {<br />
nh = 1;<br />
nw = aspect;<br />
}<br />
<br />
float h = nh * scale;<br />
float w = nw * scale;<br />
<br />
m_projectionMatrix = mat4::Frustum(-w / 2, w / 2, -h / 2, h / 2, 5, 10);<br />
<br />
// Set the viewport transform.<br />
glViewport(x, y, width, height);<br />
<br />
<br />
std::cout << "Initializing Print3D..." << std::endl;<br />
bool bRotate = (bool)(width/height);<br />
std::cout << "bRotate =" << bRotate << std::endl;<br />
<br />
//reinitialise Print3D<br />
if(m_Print3D.SetTextures(0, width, height, bRotate) != PVR_SUCCESS)<br />
{<br />
std::cout << "ERROR: Could Not Initialize Print3D";<br />
exit(EXIT_FAILURE);<br />
}<br />
std::cout << "...Print3D Initialized." << std::endl;<br />
<br />
}
```<br />
<br />
<br />
I put in "couts" to prove to myself that SetTextures was returning PVR_SUCCESS.<br />
<br />
<br />
Then in my render method I call Print3D at the end:<br />
<br />

void RenderingEngine::Render(const vector& visuals) //const

{

glClearColor(0.5f, 0.5f, 0.5f, 1);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);



vector::const_iterator visual = visuals.begin();

for (int visualIndex = 0; visual != visuals.end(); ++visual, ++visualIndex) {



// Set the light position.

vec4 lightPosition(0.25, 0.25, 1, 0);

glUniform3fv(m_uniforms.LightPosition, 1, lightPosition.Pointer());



// Set the model-view transform.

mat4 rotation = visual->Orientation.ToMatrix();

mat4 modelview = rotation * m_translation;

glUniformMatrix4fv(m_uniforms.Modelview, 1, 0, modelview.Pointer());



// Set the normal matrix.

// It’s orthogonal, so its Inverse-Transpose is itself!

mat3 normalMatrix = modelview.ToMat3();

glUniformMatrix3fv(m_uniforms.NormalMatrix, 1, 0, normalMatrix.Pointer());



// Set the projection transform.

glUniformMatrix4fv(m_uniforms.Projection, 1, 0, m_projectionMatrix.Pointer());



// Set the diffuse color. //FIX MAGIC NUMBER!!!

vec3 color = visual->Color * 0.75f;

glVertexAttrib4f(m_attributes.DiffuseMaterial, color.x, color.y, color.z, 1);



// Draw the surface.

int stride = sizeof(vec3) + sizeof(vec3) + sizeof(vec2);

const GLvoid* normalOffset = (const GLvoid*) sizeof(vec3);

const GLvoid* texCoordOffset = (const GLvoid*) (2 * sizeof(vec3));

GLint position = m_attributes.Position;

GLint normal = m_attributes.Normal;

GLint texCoord = m_attributes.TextureCoord;

const Drawable& drawable = m_drawables[visualIndex];

glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);

glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, stride, 0);

glVertexAttribPointer(normal, 3, GL_FLOAT, GL_FALSE, stride, normalOffset);

glVertexAttribPointer(texCoord, 2, GL_FLOAT, GL_FALSE, stride, texCoordOffset);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);

glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);

}





//Test the PVRSDK OGLES2Tools library project is imported into our project correctly



/*

Display some text.

Print3D() function allows to draw text anywhere on the screen using any color.

Param 1: Position of the text along X (from 0 to 100 scale independent)

Param 2: Position of the text along Y (from 0 to 100 scale independent)

Param 3: Scale of the text

Param 4: Colour of the text (0xAABBGGRR format)

Param 5: Formated string (uses the same syntax as printf)

*/



m_Print3D.Print3D(8.0f, 30.0f, 1.0f, 0xFFAA4040, “Hello PVRSDK”);





// Tells Print3D to do all the pending text rendering now

m_Print3D.Flush();



}

<br />
The error happens in the Flush() method on this line:<br />
<br />
<code>glDrawElements(GL_TRIANGLES, nTris * 3, GL_UNSIGNED_SHORT, m_pwFacesFont);</code><br />
<br />
<br />
<br />
I took a screen grab so you could see the values stored in the CPVRTPrint3D instance when the crash occurs:<br />
<br />
<img src="http://dev.robografix.com/share/Debug-Values.png" /><br />
<br />
<br />
It appears that m_pwFacesFont when dereferenced is 0, is this normal?<br />
<br />
This all feels a bit like magic to me - I'd expect Print3D to need to know more about my rendering setup so it could overlay its output. Am I missing something obvious here?<br />
<br />
Thanks for your help<br />
<br />
Andre.

Hi Andre.



Are you using desktop GL (as opposed to GL:ES)? If so, you need to provide a context as the first parameter to SetTextures(). Passing NULL will most probably cause a crash.



Also, *m_pwFacesFont is valid to be 0. These are vertex indices.

Hi again Andre.

I’ve just noticed that your app crashes at DrawElements. This is usually because of render state setup.

By the looks of things, your VertexAttrib pointers are set up, but before calling Print3D, you should disable these (with glDisableVertexAttribArray). Otherwise, when Print3D calls DrawElements, the render state is invalid. This may also apply to glBindBuffer.

I Arron,



I’m developing for the iPad so I am using OpenGLES 2.0.



Andre.

Did you try disabling the vertex attribute arrays before calling Print3D? And also calling glBindBuffer(GL_ARRAY_BUFFER, 0) and glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)?

Hi Arron,



Just making the changes you suggested…



I now have this:


        glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);<br />
glVertexAttribPointer(m_attributes.Position, 3, GL_FLOAT, GL_FALSE, stride, 0);<br />
glVertexAttribPointer(m_attributes.Normal, 3, GL_FLOAT, GL_FALSE, stride, normalOffset);<br />
glVertexAttribPointer(m_attributes.TextureCoord, 2, GL_FLOAT, GL_FALSE, stride, texCoordOffset);<br />
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);<br />
<br />
glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);<br />
<br />
//after draw, unbind buffers and disable vertex attributes<br />
glBindBuffer(GL_ARRAY_BUFFER, 0);<br />
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);<br />
glDisableVertexAttribArray(m_attributes.Position);<br />
glDisableVertexAttribArray(m_attributes.Normal);<br />
glDisableVertexAttribArray(m_attributes.TextureCoord);
```<br />
<br />
Then I call Print3D as before...<br />
<br />
But I get a blank screen on the iPad Simulator :(<br />
<br />
Quick question:<br />
<br />
Since I am using...<br />
<br />
<code>glVertexAttribPointer(m_attributes.Position, 3, GL_FLOAT, GL_FALSE, stride, 0);</code><br />
<br />
to set my attributes, is:<br />
<br />
<code>glDisableVertexAttribArray(m_attributes.Position);</code><br />
<br />
the right way to reset it?<br />
<br />
Andre.<br />
<br />

Hi Andre.

Yes that looks correct but you’ll also need to call glEnableVertexAttribArray() before glVertexAttribPointer(), as the for loop disables and doesn’t re-enable the state :). This will fix the black screen.



e.g

glEnableVertexAttribArray(m_attributes.Position);

Hi Arron,



I’ve just been doing some refactoring - I’ve put the calls to:



glVertexAttribPointer(m_attributes.Position, 3, GL_FLOAT, GL_FALSE, stride, 0);



in my intialization code, then inside the render function I do:


        glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);<br />
glEnableVertexAttribArray(m_attributes.Position);<br />
glEnableVertexAttribArray(m_attributes.Normal);<br />
glEnableVertexAttribArray(m_attributes.TextureCoord);<br />
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);<br />
<br />
glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);<br />
<br />
//after draw, unbind buffers and disable vertex attributes<br />
<br />
glDisableVertexAttribArray(m_attributes.Position);<br />
glDisableVertexAttribArray(m_attributes.Normal);<br />
glDisableVertexAttribArray(m_attributes.TextureCoord);<br />
glBindBuffer(GL_ARRAY_BUFFER, 0);<br />
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);<br />

```<br />
<br />
This is better! It prints the Hello PVRSDK message :) But my geometry is no longer visble :(<br />
<br />
If I comment out the Print3D calls my mesh appears again. Its like its overwriting the frame, do I have to do anything special to get one to overlay on top of the other?<br />
<br />
Andre.<br />

Hi Andre.



I’m not sure but the usual method is to first enable the vertex attribute arrays, then set the pointers and bind buffers, then call DrawElements, and then disable the arrays.



So in your case it would be:





glEnableVertexAttribArray(m_attributes.Position);

glEnableVertexAttribArray(m_attributes.Normal);

glEnableVertexAttribArray(m_attributes.TextureCoord);



glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);

glVertexAttribPointer(m_attributes.Position, 3, GL_FLOAT, GL_FALSE, stride, 0);

glVertexAttribPointer(m_attributes.Normal, 3, GL_FLOAT, GL_FALSE, stride, normalOffset);

glVertexAttribPointer(m_attributes.TextureCoord, 2, GL_FLOAT, GL_FALSE, stride, texCoordOffset);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);



glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);



glDisableVertexAttribArray(m_attributes.Position);

glDisableVertexAttribArray(m_attributes.Normal);

glDisableVertexAttribArray(m_attributes.TextureCoord);

glBindBuffer(GL_ARRAY_BUFFER, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);





Failing this, it could be a render state issue with Print3D setting a state and then not resetting it back. This has caused similar problems in the past but these issues should have been fixed. You could take a look at CPVRTPrint3D::Flush() and CPVRTPrint3D::APIRenderStates() in PVRTPrint3DAPI.cpp and see if any render states are being set which you rely on, yet don’t set on a per-frame basis.

Hi Arron,



I’ve run the app and grabbed a frame and inspected the GL calls. It appears that my GL calls get flagged as invalid after the Print3D calls, so as you say it does look like something needs to be reset or I need to set something again - almost certainly the latter :slight_smile:



I’m going to go though my code and see if I can find what I need to re-enable for each frame.



Thanks ever so much for all your help on this =D>



Andre.

Hi Arron,



I’ve found the state I needed to update, I simply have add the following to the top of my render method:


    glUseProgram(m_program);<br />
glBindTexture(GL_TEXTURE_2D, m_gridTexture);
```<br />
<br />
and it works!<br />
<br />
I also looked at the CPVRTPrint3D::APIRenderStates() method. I can see it stores existing GL state at the time it is invoked and and restores it later, but it doesn't store and restore these - not sure if it is supposed to?<br />
<br />
Either way, my program works and I'm happy chappy again :)<br />
<br />
Thanks again for all your help,<br />
<br />
Andre.

Hi Andre.

Glad you got this issue solved.

Print3D should indeed store render states but the program state is an oversight which I’ll have amended.



Regards.