CGPathRef / Bezier Curves in OpenGL-ES - opengl-es

I am considering porting an iPhone project from core animation to OpenGL-ES.
I need to render a button that is constructed from CGPathRef s.
But it seems that GL has no provision for Bezier Curves.
Can anyone provide some code that renders a Bezier Curve in GL?

This will accept a series of points to draw a rounded bezier line. It must use point sprites. If you send it a line of three points, and a number of point sprites to draw, it will create a bezeir line. The code is based of something I found somewhere, but I cannot remember where.
It requires:
CGPoint origin - First Point
CGPoint control - Mid Point
CGPoint destination - End Point
int segments - Number of points to render.
To calculate the number of points, I use:
count = MAX(ceilf(sqrtf(([[currentStroke objectAtIndex:i+2] CGPointValue].x - [[currentStroke objectAtIndex:i] CGPointValue].x)
* ([[currentStroke objectAtIndex:i+2] CGPointValue].x - [[currentStroke objectAtIndex:i] CGPointValue].x)
+ ((invertedYThirdCoord - invertedYBegCoord) * (invertedYThirdCoord - invertedYBegCoord))) / 2), 1)*4;
Anyway, the code (in C++):
CGPoint vertices[segments];
CGPoint midPoint;
float x, y;
float t = 0.0;
for(int i = 0; i < (segments); i++)
{
x = pow(1 - t, 2) * origin.x + 2.0 * (1 - t) * t * control.x + t * t * destination.x;
y = pow(1 - t, 2) * origin.y + 2.0 * (1 - t) * t * control.y + t * t * destination.y;
vertices[i] = CGPointMake(x, y);
t += 1.0 / (segments);
}
midPoint = CGPointMake(x, 288 - y);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_POINTS, 0, segments);
Following this render as normal.

Related

Processing - creating circles from current pixels

I'm using processing, and I'm trying to create a circle from the pixels i have on my display.
I managed to pull the pixels on screen and create a growing circle from them.
However i'm looking for something much more sophisticated, I want to make it seem as if the pixels on the display are moving from their current location and forming a turning circle or something like this.
This is what i have for now:
int c = 0;
int radius = 30;
allPixels = removeBlackP();
void draw {
loadPixels();
for (int alpha = 0; alpha < 360; alpha++)
{
float xf = 350 + radius*cos(alpha);
float yf = 350 + radius*sin(alpha);
int x = (int) xf;
int y = (int) yf;
if (radius > 200) {radius =30;break;}
if (c> allPixels.length) {c= 0;}
pixels[y*700 +x] = allPixels[c];
updatePixels();
}
radius++;
c++;
}
the function removeBlackP return an array with all the pixels except for the black ones.
This code works for me. There is an issue that the circle only has the numbers as int so it seems like some pixels inside the circle won't fill, i can live with that. I'm looking for something a bit more complex like I explained.
Thanks!
Fill all pixels of scanlines belonging to the circle. Using this approach, you will paint all places inside the circle. For every line calculate start coordinate (end one is symmetric). Pseudocode:
for y = center_y - radius; y <= center_y + radius; y++
dx = Sqrt(radius * radius - y * y)
for x = center_x - dx; x <= center_x + dx; x++
fill a[y, x]
When you find places for all pixels, you can make correlation between initial pixels places and calculated ones and move them step-by-step.
For example, if initial coordinates relative to center point for k-th pixel are (x0, y0) and final coordinates are (x1,y1), and you want to make M steps, moving pixel by spiral, calculate intermediate coordinates:
calc values once:
r0 = Sqrt(x0*x0 + y0*y0) //Math.Hypot if available
r1 = Sqrt(x1*x1 + y1*y1)
fi0 = Math.Atan2(y0, x0)
fi1 = Math.Atan2(y1, x1)
if fi1 < fi0 then
fi1 = fi1 + 2 * Pi;
for i = 1; i <=M ; i++
x = (r0 + i / M * (r1 - r0)) * Cos(fi0 + i / M * (fi1 - fi0))
y = (r0 + i / M * (r1 - r0)) * Sin(fi0 + i / M * (fi1 - fi0))
shift by center coordinates
The way you go about drawing circles in Processing looks a little convoluted.
The simplest way is to use the ellipse() function, no pixels involved though:
If you do need to draw an ellipse and use pixels, you can make use of PGraphics which is similar to using a separate buffer/"layer" to draw into using Processing drawing commands but it also has pixels[] you can access.
Let's say you want to draw a low-res pixel circle circle, you can create a small PGraphics, disable smoothing, draw the circle, then render the circle at a higher resolution. The only catch is these drawing commands must be placed within beginDraw()/endDraw() calls:
PGraphics buffer;
void setup(){
//disable sketch's aliasing
noSmooth();
buffer = createGraphics(25,25);
buffer.beginDraw();
//disable buffer's aliasing
buffer.noSmooth();
buffer.noFill();
buffer.stroke(255);
buffer.endDraw();
}
void draw(){
background(255);
//draw small circle
float circleSize = map(sin(frameCount * .01),-1.0,1.0,0.0,20.0);
buffer.beginDraw();
buffer.background(0);
buffer.ellipse(buffer.width / 2,buffer.height / 2, circleSize,circleSize);
buffer.endDraw();
//render small circle at higher resolution (blocky - no aliasing)
image(buffer,0,0,width,height);
}
If you want to manually draw a circle using pixels[] you are on the right using the polar to cartesian conversion formula (x = cos(angle) * radius, y = sin(angle) * radius).Even though it's focusing on drawing a radial gradient, you can find an example of drawing a circle(a lot actually) using pixels in this answer

Quaternion translation and rotation in iOS OpenGL ES

I'm struggling with some quaternion code in iOS. I have an open cube, which i've rotated into an isometric view. i am able to rotate the cube with touch and rotate about its axis and also zoom in/out. I also have labels associated with the cube - which also need to rotate with the cube. Again, i've managed to do this.
However, i'm now trying to implement being able to drag the label (ie. translate it) from one position, to another. If we look at the image below, what i've tried to illustrate is that i want to be able to translate the label from "label from" to the position "label to". Then, when i come to rotating the cube, the label should stay in its new position and rotate with the cube. However, i'm making a cock-up of this translation and when i try rotating the cube, the label jumps to a new position since i've not set the label coordinates properly.
I have the quaternion associated with the cube.
With the following code, i have been able to translate the label properly when the quaternion is set to [0, 0, 0, 1] (so that the cube is front-on - looks like a square from this position).
- (void) rotateWithAngle:(float) radians andVector:(GLKVector3) axis andScale:(float) scale
{
if (radians != self.lastRadians
|| (axis.v[0] != self.lastAxis.v[0] || axis.v[1] != self.lastAxis.v[1] || axis.v[2] != self.lastAxis.v[2])
|| scale != self.lastScale)
{
GLKMatrix4 m = GLKMatrix4MakeTranslation(self.normX, self.normY, self.normZ);
if (radians != 0)
m = GLKMatrix4Rotate(m, radians, axis.x, -axis.y, axis.z);
m = GLKMatrix4Scale(m, scale, scale, scale);
float x = (m.m00 * m.m30) + (m.m01 * m.m31) + (m.m02 * m.m32) + (m.m03 * m.m33);
float y = (m.m10 * m.m30) + (m.m11 * m.m31) + (m.m12 * m.m32) + (m.m13 * m.m33);
float z = (m.m20 * m.m30) + (m.m21 * m.m31) + (m.m22 * m.m32) + (m.m23 * m.m33);
x /= m.m33;
y /= m.m33;
z /= m.m33;
float w = (((x+self.winSz) / (self.winSz * 2.0)) * self.parentFrame.size.width) + self.parentFrame.origin.x;
float h = (((y+self.winSz) / (self.winSz * 2.0)) * self.parentFrame.size.height) + self.parentFrame.origin.y;
self.lastRadians = radians;
self.lastAxis = axis;
self.lastScale = scale;
[self setCenter:CGPointMake(w,h)];
}
}
- (void) translateFromTouch:(UIPanGestureRecognizer *) pan
{
CGPoint translation = [pan translationInView:self];
CGPoint imageViewPosition = self.center;
GLKVector3 axis = GLKQuaternionAxis(*_quaternion);
float rot = GLKQuaternionAngle(*_quaternion);
CGFloat h = self.parentFrame.size.height;
CGFloat w = self.parentFrame.size.width;
imageViewPosition.x += translation.x;
imageViewPosition.y += translation.y;
self.center = imageViewPosition;
// recalculate the norm position
float x = ((2.0 * self.winSz * (imageViewPosition.x - self.parentFrame.origin.x)) / w) - self.winSz;
float y = ((2.0 * self.winSz * (imageViewPosition.y - self.parentFrame.origin.y)) / h) - self.winSz;
self.normX = x;
self.normY = y;
[pan setTranslation:CGPointZero inView:self];
}
These methods are hit if a label (based on a UILabel) is either dragged or the cube (or the opengl scene) is rotated.
This works when we are looking front-on, so that the x,y values can easily be converted from pixel coords into normal or world coords.
However, when the axis is not front-on, i'm struggling to figure it out. For instance, we we have the quaternion set at (0, sqrt(2)/2, 0, sqrt(2)/2) then all x translations correspond to z world coords. So how do i make this connection/calculation? I'm sure it's fairly easy but i've hit a wall with this.
(winSz i have set to 1.5. model coords very between -1 and 1)

Not getting the correct orientation of the user with respect to Kinect

I am using Microsoft Kinect in a project. One of the task that I have to accomplish is to find the orientation of the user w.r.t the Kinect sensor (when the user turns, the orientation changes)
For this, I am trying to find the angle which the line joining the shoulders makes with the x axis of Kinect.
I have come up with the following code, but it gives me very small angle values, even when I turn almost about 40 degrees.
double vector_x=skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_LEFT].x-skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_RIGHT].x;
double vector_y=skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_LEFT].y-skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_RIGHT].y;
double vector_z=skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_LEFT].z-skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_RIGHT].z;
double len1=sqrtf(vector_x * vector_x + vector_y * vector_y + vector_z * vector_z);
double vector_x1=1.0;
double vector_y1=0.0;
double vector_z1=0.0;
double len2=sqrtf(vector_x1 * vector_x1 + vector_y1 * vector_y1 + vector_z1 * vector_z1);
double dot_product = vector_x * vector_x1 + vector_y * vector_y1 + vector_z * vector_z1;
double angle = dot_product / (len1 * len2);
coor_left=Convert(vector_x)+"\t"+Convert(vector_y)+"\t"+Convert(vector_z)+"\n";
OutputDebugStringA(Convert(acos(angle)).c_str());
When I added the conversion of radians to degrees,
double angle1=angle*180.0/3.14;
I get values form -33 to -57(when I am facing the Kinect) and then to -33 again.
But in reality, it should be negative, then 0 and then positive on the other side. Where am I going wrong?
I solved it myself. I realised that I was finding the angle between incorrect vectors.
All I needed to do was to take the projection of the left and the right shoulders on the x-z plane and then reduce the problem to finding the angle between two vectors in a plane.
Here is what I did:
double CalcAngle(double p1x,double p1y, double p2x,double p2y, double p3x,double p3y, double p4x,double p4y)
{
//
// calculate the angle between the line from p1 to p2
// and the line from p3 to p4
//
double x1 = p1x - p2x;
double y1 = p1y - p2y;
double x2 = p3x - p4x;
double y2 = p3y - p4y;
//
double angle1 , angle2 , angle;
//
if (x1 != 0.0f)
angle1 = atan(y1/x1);
else
angle1 = 3.14159 / 2.0; // 90 degrees
//
if (x2 != 0.0f)
angle2 = atan(y2/x2);
else
angle2 = 3.14159 / 2.0; // 90 degrees
//
angle = fabs(angle2-angle1);
angle = angle * 180.0 / 3.14159; // convert to degrees ???
//
return angle;
}
double myangle=CalcAngle(skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_LEFT].x,skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_LEFT].z,
skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_RIGHT].x,skel.SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_RIGHT].z,
0,0,1,0);
OutputDebugStringA(Convert(myangle).c_str());
OutputDebugStringA("\n");

scale rotating boundingbox

I recently started to develop a Windows Phone game with XNA. I have problem as you might have guessed collision detection. After looking up tutorials about all the types that can be achieved I decided I will go for the basic rectangular collision detection. I have a rotating sprite and a method that calculates the bounding box every time in the Update() method so I know where it's bounding box is then I simply check for intersection between all the lines of the box with all the lines of the other sprite's boxes. But since my box is appearing square shaped and my texture of that rotating sprite is Rectangular I wanna scale the bounding box so it will be closer to the texture's size. Here is what I have for calculating the corners of the rotating bounding box:
double baseAngle = Math.Atan(this.Height / this.Width);
double len = Math.Sqrt(this.Height * this.Height / 4 + this.Width * this.Width / 4);
Vector2 tr = new Vector2((float)(Math.Sin(baseAngle + this.Rotation) * len) + this.Position.X, (float)(Math.Cos(baseAngle + this.Rotation) * len) + this.Position.Y);
Vector2 tl = new Vector2((float)(Math.Sin(Math.PI - baseAngle + this.Rotation) * len) + this.Position.X, (float)(Math.Cos(Math.PI - baseAngle + this.Rotation) * len) + this.Position.Y);
Vector2 bl = new Vector2((float)(Math.Sin(Math.PI + baseAngle + this.Rotation) * len) + this.Position.X, (float)(Math.Cos(Math.PI + baseAngle + this.Rotation) * len) + this.Position.Y);
Vector2 br = new Vector2((float)(Math.Sin(2 * Math.PI - baseAngle + this.Rotation) * len) + this.Position.X, (float)(Math.Cos(2 * Math.PI - baseAngle + this.Rotation) * len) + this.Position.Y);`
any help would be appreciated. Thanks
when you scale, it only appears bigger widht and height are same. so bounding box is same as for original. try multypllying height and width with scale number where you calculate bounding box.
and you cannot rotate bounding box, you will have to use matrix.class but you can allways use circle collision.
circle collision
int circlesColliding(int x1, int y1, int radius1, int x2, int y2, int radius2) {
//compare the distance to combined radii
int dx = x2 - x1;
int dy = y2 - y1;
int radii = radius1 + radius2;
if ((dx * dx) + (dy * dy) < radii * radii) {
return true;
} else {
return false;
}
}

OpenGL es - doesn't look 3D, looks more like 2D

Trying to make a sphere. But it so doesn't look like 3D, in fact it looks like a flat 2D picture. What am I missing here?
Thankyou
std::vector<GLfloat> ballVerts;
for(int i = 0; i <= 40; i++)
{
double lat0 = M_PI * (-0.5 + (double) (i - 1) / 40);
double z0 = sin(lat0);
double zr0 = cos(lat0);
double lat1 = M_PI * (-0.5 + (double) i / 40);
double z1 = sin(lat1);
double zr1 = cos(lat1);
for(int j = 0; j <= 40; j++)
{
double lng = 2 * M_PI * (double) (j - 1) / 40;
double x = cos(lng);
double y = sin(lng);
// normals
glNormal3f(x * zr0, y * zr0, z0);
ballVerts.push_back(x * zr0); //X
ballVerts.push_back(y * zr0); //Y
ballVerts.push_back(z0); //Z
ballVerts.push_back(0.0f);
ballVerts.push_back(1.0f);
ballVerts.push_back(0.0f);
ballVerts.push_back(1.0f); //R,G,B,A
// normals
glNormal3f(x * zr1, y * zr1, z1);
ballVerts.push_back(x * zr1); //X
ballVerts.push_back(y * zr1); //Y
ballVerts.push_back(z1); //Z
ballVerts.push_back(0.0f);
ballVerts.push_back(1.0f);
ballVerts.push_back(0.0f);
ballVerts.push_back(1.0f); //R,G,B,A
// Render code
Furthermore, I am rotating this circle, the rotation works fine, since I have light changing and it gives me an idea that, it is rotating and is infact a circle at least
glRotatef(Angle, 1.0f, 0.5f, 0.3f);
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferObject[2]);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 7*4, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3200);
glBindBuffer(GL_ARRAY_BUFFER, 0);
First off all you need to check if lighting is currently enabled using glGetIntegerv(GL_LIGHTING,&i) and maybe turn it on glEnable(GL_LIGHTING).
Then setup the glMaterial(...), glLightModel(...), glLight(...), there is tutorial http://www.cse.msu.edu/~cse872/tutorial3.html
or you can use own GLSL shaders to apply some advanced illumination, some tutorials are here http://www.lighthouse3d.com/opengl/glsl/
In some trivial cases you can just pass vertex colors via glColor3f(...) instead of using the GL lighting.
Also normals should be unit vectors or enable normalization glEnable(GL_NORMALIZE).

Resources