Drawing app on iPad using OpenGL

前端 未结 2 2026
逝去的感伤
逝去的感伤 2021-01-30 03:27

I\'m creating a drawing app ( text ) for the iPad using OpenGL. I\'ve already had a look at Apple\'s example GLPaint, and my app is now based on that code. My app should be just

相关标签:
2条回答
  • 2021-01-30 04:13

    With regards to the second part of your question (how to vary the width of the line depending on the speed of writing), you should be able to achieve this by taking advantage of UITouch's timestamp property in your touchesBegan:withEvent: and touchesMoved:withEvent: method.

    You can calculate the time difference between two subsequent touch events by storing the timestamp of the most recent UITouch object and comparing it to the new one. Dividing the distance of the swiping motion by the time difference should give you some measurement of the movement speed.

    Now all you need to do is to come up with a way to convert speed of writing into line width, which will probably come down to picking an arbitrary value and adjusting it until you're happy with the result.

    0 讨论(0)
  • 2021-01-30 04:22

    The best way to smooth the drawing is use a bezeir curve. Here is my code. It is a modified version I found on apple's dev site, but I don't remember the original link:

    CGPoint drawBezier(CGPoint origin, CGPoint control, CGPoint destination, int segments)
    {
     CGPoint vertices[segments/2];
     CGPoint midPoint;
     glDisable(GL_TEXTURE_2D);
     float x, y;
    
     float t = 0.0;
     for(int i = 0; i < (segments/2); 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);
    
     }
     //windowHeight is the height of you drawing canvas.
     midPoint = CGPointMake(x, windowHeight - y);
     glVertexPointer(2, GL_FLOAT, 0, vertices);
     glDrawArrays(GL_POINTS, 0, segments/2);
     return midPoint;
    }
    

    That will draw based on three points. The control is the midpoint, which you need to return. The new midpoint will be different than the previous. Also, if you go through the above code, it will only draw half the line. The next stroke will fill it in. This is required. my code for calling this function (the above is in C, this is in Obj-C):

       //Invert the Y axis to conform the iPhone top-down approach
       invertedYBegCoord = self.bounds.size.height - [[currentStroke objectAtIndex:i] CGPointValue].y;
       invertedYEndCoord = self.bounds.size.height - [[currentStroke objectAtIndex:i+1] CGPointValue].y;
       invertedYThirdCoord = self.bounds.size.height - [[currentStroke objectAtIndex:i+2] CGPointValue].y;
       //Figure our how many dots you need
       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))) / pointCount), 1);
    
       newMidPoint = drawBezier(CGPointMake([[currentStroke objectAtIndex:i] CGPointValue].x, invertedYBegCoord), CGPointMake([[currentStroke objectAtIndex:i+1] CGPointValue].x, invertedYEndCoord), CGPointMake([[currentStroke objectAtIndex:i+2] CGPointValue].x, invertedYThirdCoord), count);
    
       int loc = [currentStroke count]-1;
       [currentStroke insertObject:[NSValue valueWithCGPoint:newMidPoint] atIndex:loc];
       [currentStroke removeObjectAtIndex:loc-1];
    

    That code will get the mid point based on inverted iPad points, and set the 'control' as the current point.

    That will smooth out the edges. Now regarding the line width, you just need to find the speed of that drawing. It is easiest just to find the length of your line. This is easily done using component mathematics. I don't have any code for it, but here is a primer for component mathmatics from a physics site. Or you can simply divide (above) count by some number to find out how thick you need the line to be (count uses component mathematics).

    I store point data in an array called currentStroke, in case it wasn't obvious.

    That should be all you need.

    EDIT:

    To store points, you should use touchesBegin and touchesEnd:

    - (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
    {
        self.currentStroke = [NSMutableArray array];
        CGPoint point = [ [touches anyObject] locationInView:self];
        [currentStroke addObject:[NSValue valueWithCGPoint:point]];
        [self draw];
    
    }
    
    - (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
    {
        CGPoint point = [ [touches anyObject] locationInView:self];
        [currentStroke addObject:[NSValue valueWithCGPoint:point]];
        [self draw];
    }
    
    
    - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
        CGPoint point = [ [touches anyObject] locationInView:self];
        [currentStroke addObject:[NSValue valueWithCGPoint:point]];
        [self draw];
    }
    

    That is pretty much an entire drawing application there. If you are using GL_Paint, then you are already using point sprites, which this system is build on.

    0 讨论(0)
提交回复
热议问题