help with drawing a wedge with opengl es - opengl-es

I'm trying to do some basic opengl es programming to get started on the basics.
I have a drawing function tries to draw a wedge of a circle. Something is going wrong because its actually just drawing a circle.
I'm still just trying to grasp the basics of opengl es here. Heres what I have so far.
- (void)drawView
{
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glViewport(0, 0, 60, 60);
int i;
float angle_start=90;
float angle_stop=180;
int segments=360;
float const angle_step = (angle_stop - angle_start)/segments;
GLfloat *arc_vertices;
arc_vertices = malloc(2*sizeof(GLfloat) * (segments+2));
arc_vertices[0] = arc_vertices[1] = 0.0;
for(i=0; i<segments+1; i++) {
arc_vertices[2 + 2*i ] = cos(angle_start + i*angle_step);
arc_vertices[2 + 2*i + 1] = sin(angle_start + i*angle_step);
}
glVertexPointer(2, GL_FLOAT, 0, arc_vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLE_FAN, 0, segments+2);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
free(arc_vertices);
}

sin() and cos() take radians as input:
float angle_start=90;
float angle_stop=180;
int segments=360;
float const angle_step = (angle_stop - angle_start)/segments;
GLfloat* verts = (GLfloat*)malloc(2*sizeof(GLfloat) * (segments+2));
unsigned int pos = 0;
verts[pos++] = 0;
verts[pos++] = 0;
float radius = 10;
for( unsigned int i = 0; i < segments; ++i )
{
float rads = (angle_start + i*angle_step) * (3.14159 / 180);
verts[pos++] = ( cos( rads ) * radius );
verts[pos++] = ( sin( rads ) * radius );
}
glVertexPointer(2, GL_FLOAT, 0, verts);
glEnableClientState(GL_VERTEX_ARRAY);
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLE_FAN, 0, segments+1);
glDisableClientState(GL_VERTEX_ARRAY);

I see something wrong. You access vertices[i] and vertices[i+1], but i always increments by 1.
Try replacing
GLfloat vertices[720];
with
GLfloat vertices[2*720];
and replace
vertices[i]=p1;
vertices[i+1]=p2;
by
vertices[2*i]=p1;
vertices[2*i+1]=p2;

this works.
Anti aliasing is horrible but it works.
[credit1
-(void)drawcircelofSlice2
{
amt+=20;
if(amt>360.0)
{
amt=0;
}
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glViewport(20, 20, 50,50);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(30.0f, 30.0f, -1.5f, 1.5f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
float x=0;
float y=0;
//float radius=20;
float lowAngle=0;
float highAngle=(amt/360) *360;
// float highAngle=360;
float numcirclePts=360;
lowAngle=DEGREES_TO_RADIANS(lowAngle);
highAngle=DEGREES_TO_RADIANS(highAngle);
float res=numcirclePts;
float angle=lowAngle;
float anglerange=highAngle-lowAngle;
float angleAdder=anglerange/ res;
int k=0;
GLfloat verts[720];
for (int i = 0; i < numcirclePts; i++){
verts[k] = x + cos(angle) ;
verts[k+1] = y - sin(angle) ;
angle += angleAdder;
k+=2;
}
verts[0] = x;
verts[1] = y;
k = 2;
for (int i = 2; i < numcirclePts; i++){
verts[k] = verts[k];
verts[k+1] = verts[k+1];
k+=2;
}
glVertexPointer(2, GL_FLOAT, 0, verts);
glEnableClientState(GL_VERTEX_ARRAY);
glColor4f(0.0f, 0.0f, 1.0f, 0.0f);
glDrawArrays(GL_TRIANGLE_FAN, 0, numcirclePts);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
glDisableClientState(GL_VERTEX_ARRAY);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}

Related

GLSL Vertex Shader gives wrong results if I do not mention gl_Vertex

I am writing a shader to draw lines with a width, as an alternative to glLineWidth, which doesn't work above 1.0 with ANGLE, and I'd like my lines to have the same thickness on Windows. I am running on desktop OpenGL for now, though.
The vertex shader source is as follows
attribute vec3 a_startPosition;
attribute vec3 a_endPosition;
attribute float a_choice;
attribute float a_dir;
uniform mat4 u_mvpMatrix;
uniform float u_width;
uniform vec2 u_viewDims;
void main()
{
vec4 start = u_mvpMatrix*vec4(a_startPosition, 1.0);
vec4 end = u_mvpMatrix*vec4(a_endPosition, 1.0);
//gl_Vertex;
vec2 slope = normalize(end.xy - start.xy);
slope = vec2(slope.y, -slope.x);
vec2 scale = u_width/u_viewDims;
if (a_choice == 0.0)
gl_Position = vec4(start.xy + a_dir*scale*slope.xy*start.w, start.zw);
else
gl_Position = vec4(end.xy + a_dir*scale*slope.xy*end.w, end.zw);
}
See that I have gl_Vertex, unused, commented out.
int width, height;
glfwGetFramebufferSize(m_window, &width, &height);
glUseProgram(m_shaders[Shader_WideLine]->id());
GLint shaderid = m_shaders[Shader_WideLine]->id();
GLint coloc = glGetUniformLocation(shaderid, "Color");
GLint dimloc = glGetUniformLocation(shaderid, "u_viewDims");
GLint widthloc = glGetUniformLocation(shaderid, "u_width");
GLint mvploc = glGetUniformLocation(shaderid, "u_mvpMatrix");
GLint modelviewloc = glGetUniformLocation(shaderid, "u_modelview");
GLint projloc = glGetUniformLocation(shaderid, "u_projection");
GLint dirloc = glGetAttribLocation(shaderid, "a_dir");
GLint startloc = glGetAttribLocation(shaderid, "a_startPosition");
GLint endloc = glGetAttribLocation(shaderid, "a_endPosition");
GLint chloc = glGetAttribLocation(shaderid, "a_choice");
//////////
//Set Uniforms
//////////
glUniform1f(widthloc, 10);
glUniform2f(dimloc, width, height);
glUniform4f(coloc, 0.101f, 0.558f, 0.109f, 1.f);
glm::mat4 modelview;
glm::mat4 projection;
glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(modelview));
glGetFloatv(GL_PROJECTION_MATRIX, glm::value_ptr(projection));
glm::mat4 mvp = projection * modelview;
glUniformMatrix4fv(mvploc, 1, GL_FALSE, glm::value_ptr(mvp));
int numpts = 4;
GLfloat v[4][3] = {
{0,1,0},
{0,0,0},
{1,0,0},
{1,1,0}
};
//////////
// Draw (attributes)
//////////
glBegin( GL_TRIANGLE_STRIP );
glNormal3d(0.0, 0.0, 1.0);
for(int i=0; i<numpts-1; i++)
{
glVertexAttrib3fv(startloc, v[i]);
glVertexAttrib3fv(endloc, v[i+1]);
glVertexAttrib1f(chloc, 0);
glVertexAttrib1f(dirloc, -1.0f);
glVertex3d(0,0,0);
glVertexAttrib1f(dirloc, 1.0f);
glVertex3d(0,0,0);
glVertexAttrib1f(chloc, -1);
glVertexAttrib1f(dirloc, -1.0f);
glVertex3d(0,0,0);
glVertexAttrib1f(dirloc, 1.0f);
glVertex3d(0,0,0);
}
glEnd();
glUseProgram(0);
So I am trying to draw lines from (0,1,0) to (0,0,0) to (1,0,0) to (1,1,0) with a width of 10 pixels. In the following images is a wire cube 2x2x2 centered on the origin for reference.
When called as presented I get the unexpected result of this
If I uncomment gl_Vertex; in the shader, so that it is unused but referenced, I get this expected result.
What is the reason that this could happen?
gl_ModelViewProjectionMatrix is not a valid ES 2.0 vertex shader built-in variable.
You'll have to pass in your MVP via uniform.

Drawing Simple Triangles in 3D.. Only one shows up on Emulator, on real device - No Triangles

// Front face
fPyramid[0] = 0.0f; fPyramid[1] = 5.0f; fPyramid[2] = 0.0f;
fPyramid[3] = -3.0f; fPyramid[4] = 0.0f; fPyramid[5] = 3.0f;
fPyramid[6] = 3.0f; fPyramid[7] = 0.0f; fPyramid[8] = 3.0f;
// Left face
fPyramid[18] = 0.0f; fPyramid[19] = 5.0f; fPyramid[20] = 0.0f;
fPyramid[21] = -3.0f; fPyramid[22] = 0.0f; fPyramid[23] = -3.0f;
fPyramid[24] = -3.0f; fPyramid[25] = 0.0f; fPyramid[26] = 3.0f;
// Back face
fPyramid[9] = 0.0f; fPyramid[10] = 5.0f; fPyramid[11] = 0.0f;
fPyramid[12] = 3.0f; fPyramid[13] = 0.0f; fPyramid[14] = -3.0f;
fPyramid[15] = -3.0f; fPyramid[16] = 0.0f; fPyramid[17] = -3.0f;
// Right face
fPyramid[27] = 0.0f; fPyramid[28] = 5.0f; fPyramid[29] = 0.0f;
fPyramid[30] = 3.0f; fPyramid[31] = 0.0f; fPyramid[32] = 3.0f;
fPyramid[33] = 3.0f; fPyramid[34] = 0.0f; fPyramid[35] = -3.0f;
for(int i = 0; i < 4 ; i++)
{
fPyramidColor[i*9] = 1.0f; fPyramidColor[i*9+1] = 0.0f; fPyramidColor[i*9+2] = 0.0f;
if(i < 2)
{
fPyramidColor[i*9+1] = 0.0f; fPyramidColor[i*9+4] = 1.0f; fPyramidColor[i*9+5] = 0.0f;
fPyramidColor[i*9+2] = 0.0f; fPyramidColor[i*9+7] = 0.0f; fPyramidColor[i*9+8] = 1.0f;
}
else
{
fPyramidColor[i*9+2] = 0.0f; fPyramidColor[i*9+7] = 1.0f; fPyramidColor[i*9+8] = 0.0f;
fPyramidColor[i*9+1] = 0.0f; fPyramidColor[i*9+4] = 0.0f; fPyramidColor[i*9+5] = 1.0f;
}
}
...
glBindBuffer(GL_ARRAY_BUFFER, uiVBO[0]);
glBufferData(GL_ARRAY_BUFFER, 36*sizeof(float), fPyramid, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, uiVBO[1]);
glBufferData(GL_ARRAY_BUFFER, 36*sizeof(float), fPyramidColor, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
****************************************************************
//Shaders
****************************************************************
char vShaderStr[] =
"uniform mat4 projectionMatrix; \n"
"uniform mat4 modelViewMatrix; \n"
"attribute vec3 vPosition; \n"
"attribute vec3 inColor; \n"
"varying vec3 theColor; \n"
"void main() \n"
"{ \n"
" gl_Position = projectionMatrix*modelViewMatrix*vec4(vPosition, 1.0); \n"
" theColor = inColor; \n"
"} \n";
char fShaderStr[] =
"varying vec3 theColor; \n"
"void main() \n"
"{ \n"
" gl_FragColor = vec4(theColor, 1.0); \n"
"} \n";
****************************************************************
//in drawframe() function
****************************************************************
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindBuffer(GL_ARRAY_BUFFER, uiVBO[0]);
glEnableVertexAttribArray(0);//0 is or position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, uiVBO[1]);
glEnableVertexAttribArray(2);//2 is for colors
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
int iModelViewLoc = glGetUniformLocation(globalProgramObject, "modelViewMatrix");
int iProjectionLoc = glGetUniformLocation(globalProgramObject, "projectionMatrix");
glUniformMatrix4fv(iProjectionLoc, 1, GL_FALSE, getPerspectiveMatrixInFloat());
ESMatrix mModelView = ogmLookAt(0, 15, 40, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
ESMatrix mCurrent = ogmRotate(&mModelView, fRotationAngle, 0.0f, 1.0f, 0.0f);
ogmTranslate(&mCurrent, 0, 13, 35);
glUniformMatrix4fv(iModelViewLoc, 1, GL_FALSE, getCurrentMatrixInFloat(mCurrent));
//and finally draw arrays
glDrawArrays(GL_TRIANGLE_STRIP, 0, 12);
fRotationAngle is changing with 0.01.
this is the code, and the output is
This is the output on emulator. On real device I do not see anything. Just WHITE screen(changing from black to white is a mental peace!)
I am out of tries. Have tries changing geometry to just 2 triangles, but I get to see only one. What is wrong with this?
Your shaders should not compile on ES2. According to the GLES Shading Language 1.0.17 spec (which is relevant for ES2.0), there are no layout qualifiers, and there is no in/out (just like with GLSL <=1.20 on desktop GL), but you have to use attribute for vertex shader inputs and varying for communication between vertex and fragment shader.
You have to use glBindAttribLocation before linking the program to assign the attribute indices to your shader inputs (or query the ones the GL assigned if you do not specify them).
As a side note: currently, you try to assign index 1 for the color in the shader, but are using 2 in the client code.

Upgrading code from OpenGL ES 1.0 to 2.0

I'm just working through the twee jump project which is written in cocos2d 1.0 found here
I'm having trouble converting this section of the code to OpenGL ES 2.0. I need at least 10 reputations to post a picture but a picture of the errors I get when I try to build and run can be found here:
- (void)draw {
[super draw];
if(currentScorePosition < 0) return;
glColor4f(0.0f, 0.0f, 0.0f, 0.2f);
float w = 320.0f;
float h = 27.0f;
float x = (320.0f - w) / 2.0f;
float y = 359.0f - currentScorePosition * h;
GLfloat vertices[4][2];
GLubyte indices[4] = { 0, 1, 3, 2 };
vertices[0][0] = x; vertices[0][1] = y;
vertices[1][0] = x+w; vertices[1][1] = y;
vertices[2][0] = x+w; vertices[2][1] = y+h;
vertices[3][0] = x; vertices[3][1] = y+h;
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}

OpenGL—ES 1.0 2d rounded rectangle

How to make rounded rectangle in OpenGL, or any polygon with rounded corners?
Using polygons
If using polygons is absolutely required, for example if objects with rounding need to be scaled or zoomed a lot or if amount of rounding needs to be controlled, it is possible to break rectangle into several sub-objects.
There are at least three rectangular parts and four corners. Calculating corner coordinates is easy. Just find a point from circle and build triangles like in picture above.
float anglerad = PI * angle / 180.0f;
float x = sinf(anglerad) * radius;
float y = cosf(anglerad) * radius;
It will still have sharp edges, but more points make corners more round. Small objects need less points than big objects.
Easy route is to use GL_TRIANGLE_FAN for corners. However with OpenGL ES it might be wise to minimize amount of OpenGL calls and just use more vertices as it is possible to build whole object as GL_TRIANGLE_STRIP.
This approached can be used with any shape. With a rectangle, angle of corner is always 90 degrees, but with other shapes angle needs to be calculated from the edges.
Using textures
Another approach is called 9-slice scaling. Rectangle and texture are broken into 9 slices. Actual rounding is in corner of a texture. Idea is that corners are not scaled, but maintain their original size. This approach is widely used pattern in UI-design allowing variable size UI-elements like buttons. Its advantage is that one rectangle needs only these 9 quads to render. But it will look bad if also corners need to be scaled and especially if texture is low resolution.
Bit of a bump but I was stuck on the same problem today, this is what I output, its created with Desktop GL, but should be very easy to convert to GLES, everything is a strip. It is probably not as optimized as it should be but if someone want to have a stab at it please be my guest ;)
typedef struct
{
float x;
float y;
} Vector2f;
void RoundRect( int x,
int y,
int width,
int height,
int radius,
int resolution )
{
float step = ( 2.0f * M_PI ) / resolution,
angle = 0.0f,
x_offset,
y_offset;
int i = 0;
unsigned int index = 0,
segment_count = ( int )( resolution / 4 );
Vector2f *top_left = ( Vector2f * ) malloc( segment_count * sizeof( Vector2f ) ),
*bottom_left = ( Vector2f * ) malloc( segment_count * sizeof( Vector2f ) ),
*top_right = ( Vector2f * ) malloc( segment_count * sizeof( Vector2f ) ),
*bottom_right = ( Vector2f * ) malloc( segment_count * sizeof( Vector2f ) ),
bottom_left_corner = { x + radius,
y - height + radius };
while( i != segment_count )
{
x_offset = cosf( angle );
y_offset = sinf( angle );
top_left[ index ].x = bottom_left_corner.x -
( x_offset * radius );
top_left[ index ].y = ( height - ( radius * 2.0f ) ) +
bottom_left_corner.y -
( y_offset * radius );
top_right[ index ].x = ( width - ( radius * 2.0f ) ) +
bottom_left_corner.x +
( x_offset * radius );
top_right[ index ].y = ( height - ( radius * 2.0f ) ) +
bottom_left_corner.y -
( y_offset * radius );
bottom_right[ index ].x = ( width - ( radius * 2.0f ) ) +
bottom_left_corner.x +
( x_offset * radius );
bottom_right[ index ].y = bottom_left_corner.y +
( y_offset * radius );
bottom_left[ index ].x = bottom_left_corner.x -
( x_offset * radius );
bottom_left[ index ].y = bottom_left_corner.y +
( y_offset * radius );
top_left[ index ].x = roundf( top_left[ index ].x );
top_left[ index ].y = roundf( top_left[ index ].y );
top_right[ index ].x = roundf( top_right[ index ].x );
top_right[ index ].y = roundf( top_right[ index ].y );
bottom_right[ index ].x = roundf( bottom_right[ index ].x );
bottom_right[ index ].y = roundf( bottom_right[ index ].y );
bottom_left[ index ].x = roundf( bottom_left[ index ].x );
bottom_left[ index ].y = roundf( bottom_left[ index ].y );
angle -= step;
++index;
++i;
}
glBegin( GL_TRIANGLE_STRIP );
{
// Top
{
i = 0;
while( i != segment_count )
{
//glColor4f( 1.0f, 0.0f, 0.0f, 1.0f );
glColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
glVertex2i( top_left[ i ].x,
top_left[ i ].y );
//glColor4f( 0.0f, 1.0f, 0.0f, 1.0f );
glColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
glVertex2i( top_right[ i ].x,
top_right[ i ].y );
++i;
}
}
// In order to stop and restart the strip.
glColor4f( 0.0f, 1.0f, 0.0f, 1.5f );
glVertex2i( top_right[ 0 ].x,
top_right[ 0 ].y );
glColor4f( 0.0f, 1.0f, 0.0f, 1.5f );
glVertex2i( top_right[ 0 ].x,
top_right[ 0 ].y );
// Center
{
//glColor4f( 0.0f, 1.0f, 0.0f, 1.0f );
glColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
glVertex2i( top_right[ 0 ].x,
top_right[ 0 ].y );
//glColor4f( 1.0f, 0.0f, 0.0f, 1.0f );
glColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
glVertex2i( top_left[ 0 ].x,
top_left[ 0 ].y );
//glColor4f( 0.0f, 0.0f, 1.0f, 1.0f );
glColor4f( 0.5f, 0.5f, 0.5f, 1.0f );
glVertex2i( bottom_right[ 0 ].x,
bottom_right[ 0 ].y );
//glColor4f( 1.0f, 1.0f, 0.0f, 1.0f );
glColor4f( 0.5f, 0.5f, 0.5f, 1.0f );
glVertex2i( bottom_left[ 0 ].x,
bottom_left[ 0 ].y );
}
// Bottom
i = 0;
while( i != segment_count )
{
//glColor4f( 0.0f, 0.0f, 1.0f, 1.0f );
glColor4f( 0.5f, 0.5f, 0.5f, 1.0f );
glVertex2i( bottom_right[ i ].x,
bottom_right[ i ].y );
//glColor4f( 1.0f, 1.0f, 0.0f, 1.0f );
glColor4f( 0.5f, 0.5f, 0.5f, 1.0f );
glVertex2i( bottom_left[ i ].x,
bottom_left[ i ].y );
++i;
}
}
glEnd();
glBegin( GL_LINE_STRIP );
//glColor4f( 0.0f, 1.0f, 1.0f, 1.0f );
glColor4f( 1.0f, 0.5f, 0.0f, 1.0f );
// Border
{
i = ( segment_count - 1 );
while( i > -1 )
{
glVertex2i( top_left[ i ].x,
top_left[ i ].y );
--i;
}
i = 0;
while( i != segment_count )
{
glVertex2i( bottom_left[ i ].x,
bottom_left[ i ].y );
++i;
}
i = ( segment_count - 1 );
while( i > -1 )
{
glVertex2i( bottom_right[ i ].x,
bottom_right[ i ].y );
--i;
}
i = 0;
while( i != segment_count )
{
glVertex2i( top_right[ i ].x,
top_right[ i ].y );
++i;
}
// Close the border.
glVertex2i( top_left[ ( segment_count - 1 ) ].x,
top_left[ ( segment_count - 1 ) ].y );
}
glEnd();
glBegin( GL_LINES );
//glColor4f( 0.0f, 1.0f, 1.0f, 1.0f );
glColor4f( 0.0f, 0.5f, 1.0f, 1.0f );
// Separator
{
// Top bar
glVertex2i( top_right[ 0 ].x,
top_right[ 0 ].y );
glVertex2i( top_left[ 0 ].x,
top_left[ 0 ].y );
// Bottom bar
glVertex2i( bottom_left[ 0 ].x,
bottom_left[ 0 ].y );
glVertex2i( bottom_right[ 0 ].x,
bottom_right[ 0 ].y );
}
glEnd();
free( top_left );
free( bottom_left );
free( top_right );
free( bottom_right );
}
To draw the rounded rectangle simply call something like inside an orthographic view:
RoundRect( 200, /* x */
400, /* y */
400, /* width */
300, /* height */
25, /* Corner radius, at least less than 140? */
64 /* need to be "dividable" by 4 */ );
I needed to draw similar rectangle, but transparent - and code above draws some of triangles overlap. Fixed that, also removed malloc, just to simplify solution. Here is my version:
typedef struct
{
float x;
float y;
} Vector2f;
//
// Draws rounded rectangle.
//
// Slightly tuned version of http://stackoverflow.com/questions/5369507/opengles-1-0-2d-rounded-rectangle
//
#define ROUNDING_POINT_COUNT 8 // Larger values makes circle smoother.
void DrawRoundRect( float x, float y, float width, float height, float* color = 0, float radius = 0.0 )
{
Vector2f top_left[ROUNDING_POINT_COUNT];
Vector2f bottom_left[ROUNDING_POINT_COUNT];
Vector2f top_right[ROUNDING_POINT_COUNT];
Vector2f bottom_right[ROUNDING_POINT_COUNT];
if( radius == 0.0 )
{
radius = min(width, height);
radius *= 0.10; // 10%
}
int i = 0;
float x_offset, y_offset;
float step = ( 2.0f * pi ) / (ROUNDING_POINT_COUNT * 4),
angle = 0.0f;
unsigned int index = 0, segment_count = ROUNDING_POINT_COUNT;
Vector2f bottom_left_corner = { x + radius, y - height + radius };
while( i != segment_count )
{
x_offset = cosf( angle );
y_offset = sinf( angle );
top_left[ index ].x = bottom_left_corner.x -
( x_offset * radius );
top_left[ index ].y = ( height - ( radius * 2.0f ) ) +
bottom_left_corner.y -
( y_offset * radius );
top_right[ index ].x = ( width - ( radius * 2.0f ) ) +
bottom_left_corner.x +
( x_offset * radius );
top_right[ index ].y = ( height - ( radius * 2.0f ) ) +
bottom_left_corner.y -
( y_offset * radius );
bottom_right[ index ].x = ( width - ( radius * 2.0f ) ) +
bottom_left_corner.x +
( x_offset * radius );
bottom_right[ index ].y = bottom_left_corner.y +
( y_offset * radius );
bottom_left[ index ].x = bottom_left_corner.x -
( x_offset * radius );
bottom_left[ index ].y = bottom_left_corner.y +
( y_offset * radius );
top_left[ index ].x = top_left[ index ].x;
top_left[ index ].y = top_left[ index ].y;
top_right[ index ].x = top_right[ index ].x;
top_right[ index ].y = top_right[ index ].y;
bottom_right[ index ].x = bottom_right[ index ].x ;
bottom_right[ index ].y = bottom_right[ index ].y;
bottom_left[ index ].x = bottom_left[ index ].x ;
bottom_left[ index ].y = bottom_left[ index ].y ;
angle -= step;
++index;
++i;
}
static GLubyte clr[] = { 156, 207, 255, 128 }; // Light blue, 50% transparent.
if( color )
glColor4fv(color);
else
glColor4ubv(clr);
glBegin( GL_TRIANGLE_STRIP );
{
// Top
for( i = segment_count - 1 ; i >= 0 ; i--)
{
glVertex2f( top_left[ i ].x, top_left[ i ].y );
glVertex2f( top_right[ i ].x, top_right[ i ].y );
}
// In order to stop and restart the strip.
glVertex2f( top_right[ 0 ].x, top_right[ 0 ].y );
glVertex2f( top_right[ 0 ].x, top_right[ 0 ].y );
// Center
glVertex2f( top_right[ 0 ].x, top_right[ 0 ].y );
glVertex2f( top_left[ 0 ].x, top_left[ 0 ].y );
glVertex2f( bottom_right[ 0 ].x, bottom_right[ 0 ].y );
glVertex2f( bottom_left[ 0 ].x, bottom_left[ 0 ].y );
// Bottom
for( i = 0; i != segment_count ; i++ )
{
glVertex2f( bottom_right[ i ].x, bottom_right[ i ].y );
glVertex2f( bottom_left[ i ].x, bottom_left[ i ].y );
}
}
glEnd();
} //DrawRoundRect
The following code is coping from my own project, I have added some comments to explain in the code.
If will draw a gradient rounded rectangle without border.
#define GLW_SMALL_ROUNDED_CORNER_SLICES 5 // How many vertexes you want of each corner
#define glwR(rgb) ((float)(((rgb) >> 16) & 0xff) / 255)
#define glwG(rgb) ((float)(((rgb) >> 8) & 0xff) / 255)
#define glwB(rgb) ((float)(((rgb)) & 0xff) / 255)
typedef struct glwVec2 {
float x;
float y;
} glwVec2;
static glwVec2 glwRoundedCorners[GLW_SMALL_ROUNDED_CORNER_SLICES] = {{0}}; // This array keep the generated vertexes of one corner
static void createRoundedCorners(glwVec2 *arr, int num) {
// Generate the corner vertexes
float slice = M_PI / 2 / num;
int i;
float a = 0;
for (i = 0; i < num; a += slice, ++i) {
arr[i].x = cosf(a);
arr[i].y = sinf(a);
}
}
createRoundedCorners(glwRoundedCorners, GLW_SMALL_ROUNDED_CORNER_SLICES);
void glwDrawRoundedRectGradientFill(float x, float y, float width, float height,
float radius, unsigned int topColor, unsigned int bottomColor) {
float left = x;
float top = y;
float bottom = y + height - 1;
float right = x + width - 1;
int i;
glDisable(GL_TEXTURE_2D);
glBegin(GL_QUAD_STRIP);
// Draw left rounded side.
for (i = 0; i < GLW_SMALL_ROUNDED_CORNER_SLICES; ++i) {
glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
bottom - radius + radius * glwRoundedCorners[i].y);
glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
top + radius - radius * glwRoundedCorners[i].y);
}
// Draw right rounded side.
for (i = GLW_SMALL_ROUNDED_CORNER_SLICES - 1; i >= 0; --i) {
glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
bottom - radius + radius * glwRoundedCorners[i].y);
glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
top + radius - radius * glwRoundedCorners[i].y);
}
glEnd();
}
If you want draw the border, here is the code.
static void glwDrawRightTopVertexs(float left, float top, float right,
float bottom, float radius) {
int i;
for (i = GLW_SMALL_ROUNDED_CORNER_SLICES - 1; i >= 0; --i) {
glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
top + radius - radius * glwRoundedCorners[i].y);
}
}
static void glwDrawRightBottomVertexs(float left, float top, float right,
float bottom, float radius) {
int i;
for (i = 0; i < GLW_SMALL_ROUNDED_CORNER_SLICES; ++i) {
glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
bottom - radius + radius * glwRoundedCorners[i].y);
}
}
static void glwDrawLeftBottomVertexs(float left, float top, float right,
float bottom, float radius) {
int i;
for (i = GLW_SMALL_ROUNDED_CORNER_SLICES - 1; i >= 0; --i) {
glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
bottom - radius + radius * glwRoundedCorners[i].y);
}
}
static void glwDrawLeftTopVertexs(float left, float top, float right,
float bottom, float radius) {
int i;
for (i = 0; i < GLW_SMALL_ROUNDED_CORNER_SLICES; ++i) {
glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
top + radius - radius * glwRoundedCorners[i].y);
}
}
void glwDrawRoundedRectBorder(float x, float y, float width, float height,
float radius, unsigned int color) {
float left = x;
float top = y;
float bottom = y + height - 1;
float right = x + width - 1;
glDisable(GL_TEXTURE_2D);
glColor3f(glwR(color), glwG(color), glwB(color));
glBegin(GL_LINE_LOOP);
glVertex2f(left, top + radius);
glwDrawLeftTopVertexs(left, top, right, bottom, radius);
glVertex2f(left + radius, top);
glVertex2f(right - radius, top);
glwDrawRightTopVertexs(left, top, right, bottom, radius);
glVertex2f(right, top + radius);
glVertex2f(right, bottom - radius);
glwDrawRightBottomVertexs(left, top, right, bottom, radius);
glVertex2f(right - radius, bottom);
glVertex2f(left + radius, bottom);
glwDrawLeftBottomVertexs(left, top, right, bottom, radius);
glVertex2f(left, bottom - radius);
glEnd();
}
#define PI_2 1.57079632679490f
#define SIN(x) SDL_sinf (x)
#define COS(x) SDL_cosf (x)
typedef struct _g2d_vertex_t g2d_vertex_t;
struct _g2d_vertex_t {
float x, y;
};
// pVertices - destination buffer
// nVertices - buffer size
// dx - width
// dy - height
// r - radius
// returnes the number of used vertices
int
__cdecl buildRoundedRect (g2d_vertex_t * pVertices, int nVertices, float dx, float dy, float r) {
float a, da;
int i1, i2, i3, i4, n;
if (nVertices < 4) { return 0; }
if (nVertices == 4) {
pVertices [0].x = 0.f; pVertices [0].y = 0.f;
pVertices [1].x = dx; pVertices [1].y = 0.f;
pVertices [2].x = dx; pVertices [2].y = dy;
pVertices [3].x = 0.f; pVertices [3].y = dy;
return nVertices;
}
n = nVertices >> 2;
if (r > dx / 2.f) { r = dx / 2.f; }
if (r > dy / 2.f) { r = dy / 2.f; }
a = 0.f;
da = PI_2 / (float) (n - 1);
for (i1 = 0, i2 = (n << 1) - 1, i3 = n << 1, i4 = (n << 2) - 1; i1 < n; i1++, i2--, i3++, i4--, a += da) {
float cosA = COS (a), sinA = SIN (a);
pVertices [i1].x = (dx - r) + r * cosA; pVertices [i1].y = (dy - r) + r * sinA;
pVertices [i2].x = r - r * cosA; pVertices [i2].y = (dy - r) + r * sinA;
pVertices [i3].x = r - r * cosA; pVertices [i3].y = r - r * sinA;
pVertices [i4].x = (dx - r) + r * cosA; pVertices [i4].y = r - r * sinA;
}
return n << 2;
}
void drawRoundedRect () {
g2d_vertex_t vertices [50];
glColor3f (0.3f, 0.5f, 0.2f);
glVertexPointer (2, GL_FLOAT, 0, vertices);
glEnableClientState (GL_VERTEX_ARRAY);
glDrawArrays (GL_LINE_LOOP, 0, buildRoundedRect (vertices, 50 /* max count of vertices to use: 4 - 50 */, 150.f, 80.f, 20.f));
}
I came across this fixing a crash in some open-source software - the non-GL version worked fine but basically the intention was to implement a rounded rectangle but the developer was too lazy for that and decided to force a crash instead :-(
Although I think #vime's answer is succinct and complete, I have seen lots of similar examples, none of which gave me any confidence and that I thought were non-obvious, so here's mine for the record... the calling function
implements the 4-corners ( code snippet )...
glBegin(GL_POLYGON);
// top-left corner
DrawGLRoundedCorner(x, y + radius, 3 * PI / 2, PI / 2, radius);
// top-right
DrawGLRoundedCorner(x + size_x - radius, y, 0.0, PI / 2, radius);
// bottom-right
DrawGLRoundedCorner(x + size_x, y + size_y - radius, PI / 2, PI / 2, radius);
// bottom-left
DrawGLRoundedCorner(x + radius, y + size_y, PI, PI / 2, radius);
glEnd();
... and the arc-section function DrawGLRoundedCorner(). Note that this assumes that glBegin() has already been called and plots both the start and the end of the arc - which is why you don't need to explicitly add the vertices at the end of the sides.
void DrawGLRoundedCorner(int x, int y, double sa, double arc, float r) {
// centre of the arc, for clockwise sense
float cent_x = x + r * cos(sa + PI / 2);
float cent_y = y + r * sin(sa + PI / 2);
// build up piecemeal including end of the arc
int n = ceil(N_ROUNDING_PIECES * arc / PI * 2);
for (int i = 0; i <= n; i++) {
double ang = sa + arc * (double)i / (double)n;
// compute the next point
float next_x = cent_x + r * sin(ang);
float next_y = cent_y - r * cos(ang);
glVertex2f(next_x, next_y);
}
}
By using a different glBegin such as with GL_LINE_LOOP I think you would end up with a non-filled rounded rectangle. For larger corner radii there might be a need to use various anti-aliasing hints or the like to make it look prettier, but there are other posts regarding that.
Hope that helps someone.
You can also make triangles instead of rectangles to bevel the edges.

How to draw a dotted line using OpenGL ES 1?

To draw a dotted line in OpenGL I can use glLineStipple, but how do I achieve the same effect in OpenGL ES 1?
Lines can be textured, just like triangles. Enable alpha testing, apply an alpha texture, set up some texture coordinates, and enjoy.
Actually i have realized the doted line or the dashed line using for loops but it still make non sense to use it as a line type link to the drawing method, here is the code of my doted line and dashed line below:
doted line:
(void)drawVerticalDotedInternalGrid{
float a,b;
int drawCount =0;
GLfloat dotedInternalGrid[1296];
for (a = -0.5f; a <= 0.5f; a +=0.5f) {
for (b = -0.875f; b <=0.925f; b += 0.025f)
{
dotedInternalGrid[drawCount] = b;
drawCount++;
dotedInternalGrid[drawCount] = a;
drawCount++;
};
};
glPointSize(1.0f);
glColor4f(0.863f,0.863f,0.863f,0.8f); //line color
glVertexPointer(2, GL_FLOAT, 0, dotedInternalGrid);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_POINTS, 0, 648);
glDisableClientState(GL_VERTEX_ARRAY);
}
dashed line:
(void)drawVerticalDashedInternalGridH{
GLfloat dashedLine[1296];
float a,b;
int i =0;
//-0.4----0.4 // -0.875----0.900
for (a = -0.4f; a <= 0.4f; a +=0.1f) {
for (b =-0.825f; b <=0.950f; b+=0.025f) {
dashedLine[i] = b;
i++;
dashedLine[i] = a;
i++;
};
};
//glLineWidth(1.0f);
glColor4f(0.863f,0.863f,0.863f,1.f); //line color
glVertexPointer(2, GL_FLOAT, 0, dashedLine);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_LINES, 0, 648);
glDisableClientState(GL_VERTEX_ARRAY);
}
of course ye can see the code is drawing in a rectangle area of certain coordinates,the bother things is how to figure out the dotedInternalGrid[1296]; this size of array dynamically for draw method use and the number of lines to draw as well.
To explain it easily, I have put drawHorizontalDashedLine() first.
To understand, click this image.
I cannot put an image on this post because of my reputation.
Visualizing the Vertices
+(void)drawHorizontalDashedLine:(GLfloat)x1 x2:(GLfloat)x2 y:(GLfloat)y {
//Parameters
GLfloat DASH_LENGTH = 4.0f;
GLfloat GAP_LENGTH = 2.0f;
GLfloat LINE_THICKNESS = 1.5f;
//Calculate how many dashes require to draw the whole line
GLfloat fHorizontalLength = fabsf(x2-x1);
int nDashedLineCount = fHorizontalLength / (DASH_LENGTH + GAP_LENGTH);
int nVerticesSize = nDashedLineCount * 4; //A dashed line has 4 values(2 points)
//Vertex
GLfloat vertices[nVerticesSize];
//The first dashed line vertices
vertices[0] = (x1 < x2)? x1 : x2;
vertices[1] = y;
vertices[2] = (x1 < x2)? x1 : x2 + DASH_LENGTH;
vertices[3] = y;
//The other vertices of dashed lines
for (int nIndex=4; nIndex < nVerticesSize; nIndex=nIndex+4) {
vertices[nIndex] = vertices[nIndex-2] + GAP_LENGTH;
vertices[nIndex+1] = y;
vertices[nIndex+2] = vertices[nIndex] + DASH_LENGTH;
vertices[nIndex+3] = y;
//NSLog(#"Point1(%.2f, %.2f)", vertices[nIndex], vertices[nIndex+1]);
//NSLog(#"Point2(%.2f, %.2f)", vertices[nIndex+2], vertices[nIndex+3]);
}
//Draw the arrays
glPushMatrix();
glLineWidth(LINE_THICKNESS);
glVertexPointer (2, GL_FLOAT, 0, vertices);
glDrawArrays (GL_LINES, 0, nVerticesSize/2);
glPopMatrix();
}
drawDashedLine().
I used the trigonometric function to get lengths.
+(void)drawDashedLine:(CGPoint)point1 point2:(CGPoint)point2 {
//Parameters
GLfloat DASH_LENGTH = 3.0f;
GLfloat GAP_LENGTH = 1.0f;
GLfloat LINE_THICKNESS = 1.5f;
//Calculate how many dashes require to draw the whole line
GLfloat fWidth = point2.x - point1.x;
GLfloat fHeight = point2.y - point1.y;
GLfloat fRadian = atan2(fHeight, fWidth);
float fLineLength = sqrtf(powf(fWidth, 2) + powf(fHeight, 2));
int nDashedLineCount = fabsf(fLineLength / (DASH_LENGTH + GAP_LENGTH));
int nVerticesSize = nDashedLineCount * 4; //A dashed line has 4 values(2 points)
//Vertex
GLfloat vertices[nVerticesSize];
//The first dashed line vertices
vertices[0] = point1.x;
vertices[1] = point1.y;
vertices[2] = point1.x + cosf(fRadian) * DASH_LENGTH;
vertices[3] = point1.y + sinf(fRadian) * DASH_LENGTH;
//The other vertices of dashed lines
for (int nIndex=4; nIndex < nVerticesSize; nIndex=nIndex+4) {
vertices[nIndex] = vertices[nIndex-2] + cosf(fRadian) * GAP_LENGTH;
vertices[nIndex+1] = vertices[nIndex-1] + sinf(fRadian) * GAP_LENGTH;
vertices[nIndex+2] = vertices[nIndex] + cosf(fRadian) * DASH_LENGTH;
vertices[nIndex+3] = vertices[nIndex+1] + sinf(fRadian) * DASH_LENGTH;
//NSLog(#"DrawDash Point1(%.2f, %.2f)", vertices[nIndex], vertices[nIndex+1]);
//NSLog(#"DrawDash Point2(%.2f, %.2f)", vertices[nIndex+2], vertices[nIndex+3]);
}
//Draw the arrays
glPushMatrix();
glLineWidth(LINE_THICKNESS);
glVertexPointer (2, GL_FLOAT, 0, vertices);
glDrawArrays (GL_LINES, 0, nVerticesSize/2);
glPopMatrix();
}
glPushAttrib(GL_ENABLE_BIT);
# glPushAttrib is done to return everything to normal after drawing
glLineStipple(1, 0xAAAA); # [1]
glEnable(GL_LINE_STIPPLE);
glBegin(GL_LINES);
glVertex3f(-.5,.5,-.5);
glVertex3f(.5,.5,-.5);
glEnd();
glPopAttrib();

Resources