Drawing with OpenGL - objective-c

I'm working on a program which will calculate the centroids of some polygons. I have the centroid calculations in place. I would like to display the polygons with OpenGL. I have an OpenGL window up and running already.
In the OpenGL class there is a method, drawRect where you 'draw' the vertices to screen. I have however got the vertices I want to draw in a separate polygon class. Ideally I would like to call a draw method on a polygon, e.g.
firstPolygon.draw();
But I don't know how I would do that as the drawRect method is in the OpenGL class and thats the only way I know to draw. Can I somehow send data to the draw method from within the Polygon class? or draw directly to the screen within the polygon class?
Currently 'OpenGLView.m' contains:
#import "OpenGL/gl.h"
#import "OpenGLView.h"
#import "Poly.h"
#implementation OpenGLView
-(id)initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
if(self){
// initialise things here
}
return self;
}
-(void)drawRect:(NSRect)Rect
{
glClearColor(1.0f,1.0f,1.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0f, 0.0f, 0.0f);
glBegin(GL_LINE_LOOP);
{
glVertex3f( 0.0, 0.6, 0.0);
glVertex3f( -0.2, -0.3, 0.0);
glVertex3f( 0.2, -0.3 ,0.0);
}
glEnd();
// finish drawing
glFlush();
}
#end
And the 'Polygon' class I would like to draw in this method so I can refer to the stored vertices easily..
-(void)drawPolygon
{
// draw vertices
}

If you call your draw() function from the context of the screen draw in opengl you should be okay. That means your draw() will have to still call the opengl appropriate draw calls of course.
I'm unfamiliar with opengl on objective-c but you can probably just pass the drawing context to the draw() function and have it call drawRect that way.

Related

How to move line drawn in CGContext by touch event in Objective-C?

I used following code to draw line which works fine but How to move that drawn line within context by touch event?
- (void) drawLineFrom:(CGPoint)from to:(CGPoint)to width:(CGFloat)width
{
UIGraphicsBeginImageContext(self.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextScaleCTM(ctx, 1.0f, -1.0f);
CGContextTranslateCTM(ctx, 0.0f, -self.frame.size.height);
if (drawImage != nil) {
CGRect rect = CGRectMake(0.0f, 0.0f, self.frame.size.width, self.frame.size.height);
CGContextDrawImage(ctx, rect, drawImage.CGImage);
}
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, width);
CGContextSetStrokeColorWithColor(ctx, self.drawColor.CGColor);
CGContextMoveToPoint(ctx, from.x, from.y);
CGContextAddLineToPoint(ctx, to.x, to.y);
CGContextStrokePath(ctx);
CGContextFlush(ctx);
drawImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
drawLayer.contents = (id)drawImage.CGImage;
}
How to get reference of drawn line from CGContext ? thanks in advance.
UIGraphicsBeginImageContext() begins an image context — one that is a grid of pixels.
drawImage = UIGraphicsGetImageFromCurrentImageContext(); and drawLayer.contents = (id)drawImage.CGImage; set the contents of a layer to a captured form of that grid of pixels.
The intermediate UIGraphicsEndImageContext() ends the context you had. The context no longer exists.
So to answer you question literally:
you can't ask an image context to tell you what was drawn to it and expect it to have any higher-level insight than the individual pixels that were plotted;
you can't ask the context you drew to anything, because it no longer exists.
The normal thing to do would be to create a UIView with a bunch of properties that describe whatever you want about the line. Implement -drawRect: and in there draw the line based on the properties. When you want to update the line, update the properties. Ensure the property setters make a call to setNeedsDisplay.
In UIKit things that are interactive should be subclasses of UIView. Views draw when requested to by the system. The normal pattern is pull, not push.

Creating paths in Cocoa

How can can I create a path in Xcode 5 that resembles a half circle. I was able to make the code that goes in the .m file, but I do not know what to do in the .h file for the code that is in the .m file. I followed a tutorial and this is the code I came out with in the .m file.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 4.0);
CGContextSetStrokeColorWithColor(context,
[UIColor blueColor].CGColor);
CGRect rectangle = CGRectMake(60,170,200,80);
CGContextAddEllipseInRect(context, rectangle);
CGContextStrokePath(context);
}
The simplest way to make a view that draws itself as half a circle is to make a view that draws itself as a circle but the view is only half the width of the circle. That way, what is drawn outside the view (the other half of the circle) is not shown.

How to use glClearBuffer* in Cocoa OpenGLView to clear color buffer

I'm trying to understand how to use glClearBuffer* to change the background color in a (either single or double buffered) NSOpenGLView in Cocoa for OS X.
The following code fragment as suggested by the OpenGL Superbible fails with GL_INVALID_OPERATION:
GLfloat red[] = {1.0f, 0.0f, 0.0f, 1.0f};
glClearBufferfv(GL_COLOR, 0, red);
What do I need to supply for the second parameter?
I'm using a double buffered View extending OpenGLView.
#import "MyOpenGLView.h"
#include <OpenGL/gl3.h>
#implementation MyOpenGLView
-(void) drawRect: (NSRect) bounds
{
GLfloat red[] = {1.0f, 0.0f, 0.0f, 1.0f};
glClearBufferfv(GL_COLOR, 0, red);
GLenum e = glGetError();
// e == GL_INVALID_OPERATION after this call
// and the view is drawn in black
// The following two lines work as intended:
//glClearColor(1.0, 0.f, 0.f, 1.f);
//glClear(GL_COLOR_BUFFER_BIT);
[[self openGLContext] flushBuffer];
}
#end
Really? It is giving you GL_INVALID_OPEARATION?
This function is not supposed to generate that error... are you sure something earlier in your program did not create the error and you are mistaking the source?
The bigger problem however, is that using GL_COLOR as the buffer in this API call expects the second parameter to be an index into your set of draw buffers. It is unclear how your draw buffers are setup in this code, it is possible that you have GL_NONE. As there is no defined error behavior if you try to clear a draw buffer when GL_NONE is used, I suppose an implementation might choose to raise GL_INVALID_OPERATION.
In order for your current usage of glClearBufferfv (...) to make sense, I would expect to see something like this:
GLenum buffers [] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
GLfloat red [] = { 1.0f, 0.0f, 0.0f, 1.0f };
glDrawBuffers (2, buffers);
glClearBufferfv (GL_COLOR, 0, red);
Now this call will clear GL_COLOR_ATTACHMENT0, if you wanted to clear GL_COLOR_ATTACHMENT1, you could replace 0 with 1.

Drawings in drawRect not being displayed correctly

I want to implement freeform drawing in my app. First, I tried the code inside drawLayer:inContext: and it gave me the result I wanted.
Drawing in CALayer:
But when I decided to implement the code inside drawRect:, this happened:
Even if I draw inside the white space, the drawing is rendered outside as shown above. The code I used is exactly the same. I copy-pasted it from drawLayer:inContext: to drawRect:. I didn't change a thing, so why is this happening?
The Code:
CGContextSaveGState(ctx);
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, 1.0);
CGContextSetRGBStrokeColor(ctx, 1, 0, 0, 1);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, prevPoint.x, prevPoint.y);
for (NSValue *r in drawnPoints){
CGPoint pt = [r CGPointValue];
CGContextAddLineToPoint(ctx, pt.x, pt.y);
}
CGContextStrokePath(ctx);
CGContextRestoreGState(ctx);
I see you are using app in full screen mode where the view is centered and does not take full width of the screen.
It may be that CALayer has transform applied to it that translates the drawing from the left side of the screen to the center. This may not be the case with drawRect:. Try setting CGContext's transform matrix:
CGContextSaveGState(ctx);
CGFloat xOffset = CGRectGetMidX(screenFrame) - CGRectGetMidX(viewFrame);
CGContextTranslateCTM(ctx, xOffset, 0.0f);
// rest of drawing code
// ...
CGContextRestoreGState(ctx);

drawRect in UIView subclass doesn't update image

I have a UIView subclass that I would like to use to draw images with different blend modes.
code:
#implementation CompositeImageView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
-(void)setBlendMode:(CGBlendMode) composite
{
blender = composite;
}
-(void)setImage:(UIImage*) img
{
image = img;
}
- (void)drawRect:(CGRect)rect
{
NSLog(#"it draws");
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(c, blender);
CGContextDrawImage(c, rect, image.CGImage);
}
#end
the code that I use to set it up it is:
[testImage setImage:[UIImage imageNamed:#"Prayer_Background_Paid"]];
[testImage setBlendMode:kCGBlendModeColor];
[testImage setNeedsDisplay];
I am using the interface builder to place a large rectangular UIView, and then set its class to CompositeImageView. However, it still draws as a large white square. Even if I comment out everything inside drawRect, it still draws the white square. However, it IS calling drawRect, because "it draws" is being logged.
Are you sure kCGBlendModeColor is what you want? From the Apple doc:
Uses the luminance values of the background with the hue and
saturation values of the source image.
It seems that if it was a white background, the blended image would also appear white.