Cairo - overlapping lines - "deadzone" with no draw - cairo

I have multiple lines in Cairo. I want to have a "deadzone" around the line, so if I render multiple overlapping lines, they are not overlapping.
Something line on image below.

Here is a sample program that draws the later lines first in white with a larger line width and then again in black with the actual line width:
#include <cairo.h>
int main()
{
cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 200, 200);
cairo_t *cr = cairo_create(s);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_paint(cr);
cairo_move_to(cr, 50, 20);
cairo_line_to(cr, 110, 160);
cairo_set_line_width(cr, 4);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke(cr);
cairo_move_to(cr, 200, 0);
cairo_line_to(cr, 60, 160);
cairo_set_line_width(cr, 15);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_stroke_preserve(cr);
cairo_set_line_width(cr, 4);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke(cr);
cairo_move_to(cr, 10, 100);
cairo_line_to(cr, 220, 50);
cairo_set_line_width(cr, 15);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_stroke_preserve(cr);
cairo_set_line_width(cr, 4);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke(cr);
cairo_surface_write_to_png(s, "out.png");
cairo_destroy(cr);
cairo_surface_destroy(s);
}
Output:
Okay, now to the background. Option 1 is to draw the lines with a transparent background and then draw the background below that via operator DEST_OVER:
#include <cairo.h>
int main()
{
/* I changed this to ARGB32 */
cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 200, 200);
cairo_t *cr = cairo_create(s);
cairo_pattern_t *p = cairo_pattern_create_linear(0, 0, 200, 200);
/* Draw the lines */
cairo_move_to(cr, 50, 20);
cairo_line_to(cr, 110, 160);
cairo_set_line_width(cr, 4);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke(cr);
cairo_move_to(cr, 200, 0);
cairo_line_to(cr, 60, 160);
cairo_set_line_width(cr, 15);
/* I changed all "drawing white" to "drawing transparency" */
cairo_save(cr);
cairo_set_source_rgba(cr, 0, 0, 0, 0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_stroke_preserve(cr);
cairo_restore(cr);
cairo_set_line_width(cr, 4);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke(cr);
cairo_move_to(cr, 10, 100);
cairo_line_to(cr, 220, 50);
cairo_set_line_width(cr, 15);
cairo_save(cr);
cairo_set_source_rgba(cr, 0, 0, 0, 0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_stroke_preserve(cr);
cairo_restore(cr);
cairo_set_line_width(cr, 4);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke(cr);
/* Draw a background below what we drew so far */
cairo_pattern_add_color_stop_rgb(p, 0, 1, 0, 0);
cairo_pattern_add_color_stop_rgb(p, 1, 0, 0, 1);
cairo_set_source(cr, p);
/* Actually, I mean DEST_OVER instead of ATOP (which I wrote in my comment) */
cairo_set_operator(cr, CAIRO_OPERATOR_DEST_OVER);
cairo_paint(cr);
cairo_surface_write_to_png(s, "out.png");
cairo_pattern_destroy(p);
cairo_destroy(cr);
cairo_surface_destroy(s);
}
Output:
Option 2 is to use a temporary surface. The lines are drawn with a transparent background to this. Afterwards, this is drawn ontop of the existing background:
#include <cairo.h>
int main()
{
cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 200, 200);
cairo_t *cr = cairo_create(s);
cairo_pattern_t *p = cairo_pattern_create_linear(0, 0, 200, 200);
/* Draw a background */
cairo_pattern_add_color_stop_rgb(p, 0, 1, 0, 0);
cairo_pattern_add_color_stop_rgb(p, 1, 0, 0, 1);
cairo_set_source(cr, p);
cairo_paint(cr);
cairo_pattern_destroy(p);
/* Draw the lines */
/* but draw them to a temporary surface */
cairo_push_group_with_content(cr, CAIRO_CONTENT_COLOR_ALPHA);
cairo_move_to(cr, 50, 20);
cairo_line_to(cr, 110, 160);
cairo_set_line_width(cr, 4);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke(cr);
cairo_move_to(cr, 200, 0);
cairo_line_to(cr, 60, 160);
cairo_set_line_width(cr, 15);
/* I changed all "drawing white" to "drawing transparency" */
cairo_save(cr);
cairo_set_source_rgba(cr, 0, 0, 0, 0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_stroke_preserve(cr);
cairo_restore(cr);
cairo_set_line_width(cr, 4);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke(cr);
cairo_move_to(cr, 10, 100);
cairo_line_to(cr, 220, 50);
cairo_set_line_width(cr, 15);
cairo_save(cr);
cairo_set_source_rgba(cr, 0, 0, 0, 0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_stroke_preserve(cr);
cairo_restore(cr);
cairo_set_line_width(cr, 4);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke(cr);
/* Now draw the temporary surface to the target surface */
cairo_pop_group_to_source(cr);
cairo_paint(cr);
cairo_surface_write_to_png(s, "out.png");
cairo_destroy(cr);
cairo_surface_destroy(s);
}
Output:

Related

How to change the perspective on a 3D cube in OpenGL ES?

I draw a cube with OpenGL ES and I want to have an above perspective on it.But I don't know what should I modify...Maybe you can help.
- (void)render:(CADisplayLink*)displayLink {
//-(void) render{
glClearColor(255.0, 255.0/255.0, 255.0/255.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
//projection
CC3GLMatrix *projection = [CC3GLMatrix matrix];
float h = 4.0f * self.frame.size.height / self.frame.size.width;
[projection populateFromFrustumLeft:-2 andRight:2 andBottom:-h/2 andTop:h/2 andNear:4 andFar:8];
glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);
CC3GLMatrix *modelView = [CC3GLMatrix matrix];
// _currentScaling += displayLink.duration * 1.0;
[modelView populateFromTranslation:CC3VectorMake(sin(30), _currentScaling , -7)];
[modelView rotateBy:CC3VectorMake(0, -15, 0)];
// [modelView scaleByY:_currentScaling];
if(_currentScaling > 2 ){
[displayLink invalidate];
_running = 1;
// scale = 0;
}
glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);
// 1
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
// 2
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE,
sizeof(Vertex), 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
// 3
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]),
GL_UNSIGNED_BYTE, 0);
[_context presentRenderbuffer:GL_RENDERBUFFER];
}
I recently started looking into OpenGL myself and found this same example. I believe what you are looking for is to change this line to change the perspective:
[modelView rotateBy:CC3VectorMake(0, -15, 0)];
and specify the degrees of rotation you want for the x,y,z axes.

GLKit & adding tints to textures

I am having issue with tinting a PNG image with GLKit.
I have a white PNG image that I load into the application and then use it to create a texture:
UIImage *image = [ UIImage imageNamed:#"brushImage" ];
NSError *error = nil;
texture_m = [[ GLKTextureLoader textureWithCGImage:image.CGImage options:nil error:&error] retain ];
if (error) {
NSLog(#"Error loading texture from image: %#",error);
}
the texture is created with no errors.
however when I want to render the texture with blend activated the colour seems to be ignored and I get a white image. I had no issues when I was doing this in OpenGL1 were the image would pick up the colour that was defined in glColor4f(). Here is my render code:
-(void)render{
if (texture_m != nil) {
effect_m.texture2d0.enabled = GL_TRUE;
effect_m.texture2d0.envMode = GLKTextureEnvModeReplace;
effect_m.texture2d0.target = GLKTextureTarget2D;
effect_m.texture2d0.name = texture_m.name;
}
[effect_m prepareToDraw];
glClear(GL_COLOR_BUFFER_BIT);
GLfloat squareVertices[] = {
50, 50,
150, 50,
50, 150,
150, 150
};
GLfloat squareTexture[] = {
0, 0,
1, 0,
0, 1,
1, 1
};
glColor4f( 1, 0, 0, 1 );
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glEnable(GL_BLEND);
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, 0, squareVertices);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 0, squareTexture );
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisable(GL_BLEND);
glDisableVertexAttribArray(GLKVertexAttribPosition);
glDisableVertexAttribArray(GLKVertexAttribTexCoord0);
}
Could anybody help to solve this issue
Thanks
Reza
I have managed to solve my problem and here is the solution
-(void)render
{
if (texture_m != nil) {
effect_m.texture2d0.enabled = GL_TRUE;
// here you need to env mode to GLKTextureEnvModeModulate rather than GLKTextureEnvModeReplace
effect_m.texture2d0.envMode = GLKTextureEnvModeModulate;
effect_m.texture2d0.target = GLKTextureTarget2D;
effect_m.texture2d0.name = texture_m.name;
}
// then here I have added the tint colour to the GLKBaseEffect class as constant colour which I imagine replaces the calls to glColor4f for OpenGL1.1
effect_m.useConstantColor = YES;
float alphaValue = 0.7;
GLKVector4 colour = GLKVector4Make( 0* alphaValue, 1* alphaValue, 1* alphaValue, alphaValue );
effect_m.constantColor = colour;
// remember multiplying the alpha value to each colour component
[effect_m prepareToDraw];
glClear(GL_COLOR_BUFFER_BIT);
GLfloat squareVertices[] = {
50, 50,
150, 50,
50, 150,
150, 150
};
GLfloat squareTexture[] = {
0, 0,
1, 0,
0, 1,
1, 1
};
// glColor4f not necessary
// glColor4f( 1, 0, 0, 1 );
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glEnable(GL_BLEND);
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, 0, squareVertices);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 0, squareTexture );
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisable(GL_BLEND);
glDisableVertexAttribArray(GLKVertexAttribPosition);
glDisableVertexAttribArray(GLKVertexAttribTexCoord0);
}

bitmap fonts in cocoa touch

Is it possible to use bitmap fonts in cocoa touch / quartz 2d? If yes how do I do that?
Look at CGContextSelectFont below:
void MyDrawText (CGContextRef myContext, CGRect contextRect)
{
float w, h;
w = contextRect.size.width;
h = contextRect.size.height;
CGAffineTransform myTextTransform;
CGContextSelectFont (myContext, "Helvetica-Bold", h/10, kCGEncodingMacRoman);
CGContextSetCharacterSpacing (myContext, 10);
CGContextSetTextDrawingMode (myContext, kCGTextFillStroke);
CGContextSetRGBFillColor (myContext, 0, 1, 0, .5);
CGContextSetRGBStrokeColor (myContext, 0, 0, 1, 1);
myTextTransform = CGAffineTransformMakeRotation (MyRadians (45));
CGContextSetTextMatrix (myContext, myTextTransform);
CGContextShowTextAtPoint (myContext, 40, 0, "Quartz 2D", 9);
}

How can I draw a series of lines using OpenGL ES on iPhone OS?

I have tried as follows (got through Google search)-
static const GLfloat vertices[] =
{
0.0, 0.0,
250.0, 280.0,
250.0, 280.0,
250.0, 500.0,
250.0, 500.0,
350.0, 500.0,
350.0, 500.0,
250.0, 280.0
};
static const GLubyte squareColors[] = {
255, 255, 255, 255,
255, 255, 255, 255
};
glDisable(GL_TEXTURE_2D);
BOOL colorArrayEnabled = glIsEnabled(GL_COLOR_ARRAY);
if (!colorArrayEnabled) {
glEnableClientState(GL_COLOR_ARRAY);
}
BOOL vertexArrayEnabled = glIsEnabled(GL_VERTEX_ARRAY);
if (!vertexArrayEnabled) {
glEnableClientState(GL_VERTEX_ARRAY);
}
glLineWidth(16.0f);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
glVertexPointer(2, GL_FLOAT, sizeof(GLfloat)*2, vertices);
glDrawArrays(GL_LINES, 0, 2);
if (!vertexArrayEnabled) {
glDisableClientState(GL_VERTEX_ARRAY);
}
if (!colorArrayEnabled) {
glDisableClientState(GL_COLOR_ARRAY);
}
glEnable(GL_TEXTURE_2D);
FYI: I am a starter in iPhone programming.
Draw your lines in Blender and export Wavefront OBJ file. Use that file with OpenGLOBJLoader class. After that you can edit vertices in OBJ file if you want.

How do I implement AABB ray cast hit checking on the iPhone

Basically, I draw a 3D cube, I can spin it around but I want to be able to touch it and know where on my cube's surface the user touched.
I'm using for setting up, generating and spinning. Its based on the Molecules code and NeHe tutorial #5.
Any help, links, tutorials and code would be greatly appreciated. I have lots of development experience but nothing much in the way of openGL and 3d.
//
// GLViewController.h
// NeHe Lesson 05
//
// Created by Jeff LaMarche on 12/12/08.
// Copyright Jeff LaMarche Consulting 2008. All rights reserved.
//
#import "GLViewController.h"
#import "GLView.h"
#implementation GLViewController
- (void)drawBox
{
static const GLfloat cubeVertices[] = {
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f,
-1.0f,-1.0f, 1.0f,
-1.0f, 1.0f,-1.0f,
1.0f, 1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
-1.0f,-1.0f,-1.0f
};
static const GLubyte cubeNumberOfIndices = 36;
const GLubyte cubeVertexFaces[] = {
0, 1, 5, // Half of top face
0, 5, 4, // Other half of top face
4, 6, 5, // Half of front face
4, 6, 7, // Other half of front face
0, 1, 2, // Half of back face
0, 3, 2, // Other half of back face
1, 2, 5, // Half of right face
2, 5, 6, // Other half of right face
0, 3, 4, // Half of left face
7, 4, 3, // Other half of left face
3, 6, 2, // Half of bottom face
6, 7, 3, // Other half of bottom face
};
const GLubyte cubeFaceColors[] = {
0, 255, 0, 255,
255, 125, 0, 255,
255, 0, 0, 255,
255, 255, 0, 255,
0, 0, 255, 255,
255, 0, 255, 255
};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
int colorIndex = 0;
for(int i = 0; i < cubeNumberOfIndices; i += 3)
{
glColor4ub(cubeFaceColors[colorIndex], cubeFaceColors[colorIndex+1], cubeFaceColors[colorIndex+2], cubeFaceColors[colorIndex+3]);
int face = (i / 3.0);
if (face%2 != 0.0)
colorIndex+=4;
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, &cubeVertexFaces[i]);
}
glDisableClientState(GL_VERTEX_ARRAY);
}
//move this to a data model later!
- (GLfixed)floatToFixed:(GLfloat)aValue;
{
return (GLfixed) (aValue * 65536.0f);
}
- (void)drawViewByRotatingAroundX:(float)xRotation rotatingAroundY:(float)yRotation scaling:(float)scaleFactor translationInX:(float)xTranslation translationInY:(float)yTranslation view:(GLView*)view;
{
glMatrixMode(GL_MODELVIEW);
GLfixed currentModelViewMatrix[16] = { 45146, 47441, 2485, 0,
-25149, 26775,-54274, 0,
-40303, 36435, 36650, 0,
0, 0, 0, 65536 };
/*
GLfixed currentModelViewMatrix[16] = { 0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 65536 };
*/
//glLoadIdentity();
//glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -10.0f, 4.0f);
// Reset rotation system
if (isFirstDrawing)
{
//glLoadIdentity();
glMultMatrixx(currentModelViewMatrix);
[self configureLighting];
isFirstDrawing = NO;
}
// Scale the view to fit current multitouch scaling
GLfixed fixedPointScaleFactor = [self floatToFixed:scaleFactor];
glScalex(fixedPointScaleFactor, fixedPointScaleFactor, fixedPointScaleFactor);
// Perform incremental rotation based on current angles in X and Y
glGetFixedv(GL_MODELVIEW_MATRIX, currentModelViewMatrix);
GLfloat totalRotation = sqrt(xRotation*xRotation + yRotation*yRotation);
glRotatex([self floatToFixed:totalRotation],
(GLfixed)((xRotation/totalRotation) * (GLfloat)currentModelViewMatrix[1] + (yRotation/totalRotation) * (GLfloat)currentModelViewMatrix[0]),
(GLfixed)((xRotation/totalRotation) * (GLfloat)currentModelViewMatrix[5] + (yRotation/totalRotation) * (GLfloat)currentModelViewMatrix[4]),
(GLfixed)((xRotation/totalRotation) * (GLfloat)currentModelViewMatrix[9] + (yRotation/totalRotation) * (GLfloat)currentModelViewMatrix[8])
);
// Translate the model by the accumulated amount
glGetFixedv(GL_MODELVIEW_MATRIX, currentModelViewMatrix);
float currentScaleFactor = sqrt(pow((GLfloat)currentModelViewMatrix[0] / 65536.0f, 2.0f) + pow((GLfloat)currentModelViewMatrix[1] / 65536.0f, 2.0f) + pow((GLfloat)currentModelViewMatrix[2] / 65536.0f, 2.0f));
xTranslation = xTranslation / (currentScaleFactor * currentScaleFactor);
yTranslation = yTranslation / (currentScaleFactor * currentScaleFactor);
// Grab the current model matrix, and use the (0,4,8) components to figure the eye's X axis in the model coordinate system, translate along that
glTranslatef(xTranslation * (GLfloat)currentModelViewMatrix[0] / 65536.0f, xTranslation * (GLfloat)currentModelViewMatrix[4] / 65536.0f, xTranslation * (GLfloat)currentModelViewMatrix[8] / 65536.0f);
// Grab the current model matrix, and use the (1,5,9) components to figure the eye's Y axis in the model coordinate system, translate along that
glTranslatef(yTranslation * (GLfloat)currentModelViewMatrix[1] / 65536.0f, yTranslation * (GLfloat)currentModelViewMatrix[5] / 65536.0f, yTranslation * (GLfloat)currentModelViewMatrix[9] / 65536.0f);
// Black background, with depth buffer enabled
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
[self drawBox];
}
- (void)configureLighting;
{
const GLfixed lightAmbient[] = {13107, 13107, 13107, 65535};
const GLfixed lightDiffuse[] = {65535, 65535, 65535, 65535};
const GLfixed matAmbient[] = {65535, 65535, 65535, 65535};
const GLfixed matDiffuse[] = {65535, 65535, 65535, 65535};
const GLfixed lightPosition[] = {30535, -30535, 0, 0};
const GLfixed lightShininess = 20;
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
glMaterialxv(GL_FRONT_AND_BACK, GL_AMBIENT, matAmbient);
glMaterialxv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiffuse);
glMaterialx(GL_FRONT_AND_BACK, GL_SHININESS, lightShininess);
glLightxv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
glLightxv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
glLightxv(GL_LIGHT0, GL_POSITION, lightPosition);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_NORMALIZE);
}
-(void)setupView:(GLView*)view
{
const GLfloat zNear = 0.1,
zFar = 1000.0,
fieldOfView = 60.0;
GLfloat size;
glMatrixMode(GL_PROJECTION);
glEnable(GL_DEPTH_TEST);
size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
CGRect rect = view.bounds;
glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size /
(rect.size.width / rect.size.height), zNear, zFar);
glViewport(0, 0, rect.size.width, rect.size.height);
glScissor(0, 0, rect.size.width, rect.size.height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glTranslatef(0.0f, 0.0f, -6.0f);
isFirstDrawing = YES;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)dealloc
{
[super dealloc];
}
#end
In order to implement Ray cast hit checking, you should check these sources:
http://www.mvps.org/directx/articles/rayproj.htm
http://bookofhook.com/mousepick.pdf
http://eigenclass.blogspot.com/2008/10/opengl-es-picking-using-ray-boundingbox.html
Basically, first, create a 3D ray from a 2D touch. Then use that ray to check for intersection with objects in your world. You should create the matrix inverse of your current matrix, and from the inverse matrix you can create start and end position using your near and far clip plane. and then when calculating the near and far points you should apply the projection settings.
BTW: In my project, my point recognition is based on color unique pixel comparison rather than ray cast hit check. It is much easier to implement hit check with just finding unique colors. Only a suggestion, hope it helps :)
cheers,
Guvener