By now points can be drawn with the following code:
// SETUP FOR VERTICES
GLfloat points[graph->vertexCount * 6];
for (int i = 0 ; i < graph->vertexCount; i++)
{
points[i*6] = (graph->vertices[i].x / (backingWidth/2) ) - 1;
points[i*6+1] = -(graph->vertices[i].y / (backingHeight/2) ) + 1;
points[i*6+2] = 1.0;
points[i*6+3] = 0.0;
points[i*6+4] = 0.0;
points[i*6+5] = 1.0;
}
glEnable(GL_POINT_SMOOTH);
glPointSize(DOT_SIZE*scale);
glVertexPointer(2, GL_FLOAT, 24, points);
glColorPointer(4, GL_FLOAT, 24, &points[2]);
glDrawArrays(GL_POINTS, 0, graph->vertexCount);
The points are rendered with red color, and I want to add a white outline outside the points. How can I draw outline of the point?
Question for better displaying
Follow #BDL 's instruction adding bigger points under the red points as outline, they look good.
outlinePoints[i*6] = (graph->vertices[i].x / (backingWidth/2) ) - 1;
outlinePoints[i*6+1] = -(graph->vertices[i].y / (backingHeight/2) ) + 1;
outlinePoints[i*6+2] = 0.9;
outlinePoints[i*6+3] = 0.9;
outlinePoints[i*6+4] = 0.9;
outlinePoints[i*6+5] = 1.0;
But when one point overlaps another point, it's outline is covered by the red point, since the outline points are rendered before all the red points.
I think the right solution is to render one outline point and red point one by one. How to do that?
If you want to render outlines for each point separately, then you can simply render a slightly larger white point first and then render the red point over it. With depth-testing enabled, you might have to adjust the polygon offset when rendering the red point to prevent them from getting hidden behind the white ones.
Related
With Quartz 2D we can transform our views on the x, yand z axis.
In some cases we could even make them look 3D by changing the values of the matrixes.
I was wondering if it could be possible to transform a view into a cylinder shape like in the following picture?
Please ignore the top part of the cylinder. I am more curious to know whether it would be possible warping an UIView around like the side of the cylinder as in the image.
Is that possible only making use of Quartz 2D, layers and transformations (not OpenGL)? If not, is it possible to at least draw it in CGContext to make a view appear like so?
You definitely can't do this with a transform. What you could do is create your UIView off-screen, get the context for the view, get an image from that, and then map the image to a new image, using a non-linear mapping.
So:
Create an image context with UIGraphicsBeginImageContext()
Render the view there, with view.layer.renderInContext()
Get an image of the result with CGBitmapContextCreateImage()
Write a mapping function that takes the x/y screen coordinates and maps them to coordinates on the cylinder.
Create a new image the size of the screen view, and call the mapping
function to copy pixels from the source to the destination.
Draw the destination bitmap to the screen.
None of these steps is particularly-difficult, and you might come up with various ways to simplify. For example, you can just render strips of the original view, offsetting the Y coordinate based on the coordinates of a circle, if you are okay with not doing perspective transformations.
If you want the view to actually be interactive, then you'd need to do the transform in the opposite direction when handling touch events.
No you can't bend a view using a transform.
The transform can only manipulate the four corners of the view so no matter what you do it will still be a plane.
I realize this goes beyond Quartz2D... You could try adding SceneKit.
Obtain the view's image via UIGraphicsBeginImageContext(), view.layer.renderInContext(), CGBitmapContextCreateImage().
Create a SCNMaterial with the diffuse property set to the image of your view
Create an SCNCylinder and apply the material to it.
Add the cylinder to an SCNScene.
Create an SCNView and set its scene.
Add the SCNView to your view hierarchy.
Reference : Using OpenGL ES 2.0 with iOS, how do I draw a cylinder between two points?
I have also used the same code for one of my project:
Check this one where it is mentioned to draw cone shape; it's dated but after adapting the algorithm, it works.
See code below for solution. Self represents the mesh and contains the vertices, indices, and such.
- (instancetype)initWithOriginRadius:(CGFloat)originRadius
atOriginPoint:(GLKVector3)originPoint
andEndRadius:(CGFloat)endRadius
atEndPoint:(GLKVector3)endPoint
withPrecision:(NSInteger)precision
andColor:(GLKVector4)color
{
self = [super init];
if (self) {
// normal pointing from origin point to end point
GLKVector3 normal = GLKVector3Make(originPoint.x - endPoint.x,
originPoint.y - endPoint.y,
originPoint.z - endPoint.z);
// create two perpendicular vectors - perp and q
GLKVector3 perp = normal;
if (normal.x == 0 && normal.z == 0) {
perp.x += 1;
} else {
perp.y += 1;
}
// cross product
GLKVector3 q = GLKVector3CrossProduct(perp, normal);
perp = GLKVector3CrossProduct(normal, q);
// normalize vectors
perp = GLKVector3Normalize(perp);
q = GLKVector3Normalize(q);
// calculate vertices
CGFloat twoPi = 2 * PI;
NSInteger index = 0;
for (NSInteger i = 0; i < precision + 1; i++) {
CGFloat theta = ((CGFloat) i) / precision * twoPi; // go around circle and get points
// normals
normal.x = cosf(theta) * perp.x + sinf(theta) * q.x;
normal.y = cosf(theta) * perp.y + sinf(theta) * q.y;
normal.z = cosf(theta) * perp.z + sinf(theta) * q.z;
AGLKMeshVertex meshVertex;
AGLKMeshVertexDynamic colorVertex;
// top vertex
meshVertex.position.x = endPoint.x + endRadius * normal.x;
meshVertex.position.y = endPoint.y + endRadius * normal.y;
meshVertex.position.z = endPoint.z + endRadius * normal.z;
meshVertex.normal = normal;
meshVertex.originalColor = color;
// append vertex
[self appendVertex:meshVertex];
// append color vertex
colorVertex.colors = color;
[self appendColorVertex:colorVertex];
// append index
[self appendIndex:index++];
// bottom vertex
meshVertex.position.x = originPoint.x + originRadius * normal.x;
meshVertex.position.y = originPoint.y + originRadius * normal.y;
meshVertex.position.z = originPoint.z + originRadius * normal.z;
meshVertex.normal = normal;
meshVertex.originalColor = color;
// append vertex
[self appendVertex:meshVertex];
// append color vertex
[self appendColorVertex:colorVertex];
// append index
[self appendIndex:index++];
}
// draw command
[self appendCommand:GL_TRIANGLE_STRIP firstIndex:0 numberOfIndices:self.numberOfIndices materialName:#""];
}
return self;
}
I'm developing an app that has to draw 320 vertical gradient lines on a portrait iPhone screen where each gradient line is either 1px or 2px wide (non-retina vs retina). Each gradient line has 1000 positions, with each position able to have a unique color. These 1000 colors (floats) sit in a C-style 2D array (an array of arrays, 320 arrays of 1000 colors)
Currently, the gradient lines are drawn in a For Loop inside the drawRect method of a custom UIView. The problem I'm having is that it takes longer than ONE second to cycle through the For Loop and draw all 320 lines. Within that ONE second, I have another thread that's updating the color arrays and but since it takes longer than ONE second to draw, I don't see every update. I see every second or third update.
I'm using the exact same procedure in my Android code, which has no problems drawing 640 gradient lines (double the amount) multiple times in a second using a SurfaceView. My Android app never misses an update.
If you look at the Android code, it actually draws gradient lines to TWO separate canvases. The array size is dynamic and can be up to half the landscape resolution width of an Android phone (ex 1280 width = 1280/2 = 640 lines). Since the Android app is fast enough, I allow landscape mode. Even with the double the data as an iPhone and drawing to two separate canvases, the Android code runs multiple times a second. The iPhone code with half the number of lines and only drawing to a single context can not draw in under a second.
Is there a faster way to draw 320 vertical gradient lines (each with 1000 positions) on an iPhone?
Is there a hardware accelerated SurfaceView equivalent for iOS that can draw many gradients really fast?
//IPHONE - drawRect method
int totalNumberOfColors = 1000;
int i;
CGFloat *locations = malloc(totalNumberOfColors * sizeof locations[0]);
for (i = 0; i < totalNumberOfColors; i++) {
float division = (float)1 / (float)(totalNumberOfColors - 1);
locations[i] = i * division;
}
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
for (int k = 0; k < 320; k++) {
CGFloat * colorComponents = arrayOfFloatArrays[k];
CGGradientRef gradient = CGGradientCreateWithColorComponents(
colorSpace,
colorComponents,
locations,
(size_t)(totalNumberOfColors));
CGRect newRect;
if (currentPositionOffset >=320) {
newRect = CGRectMake(0, 0, 1, CGRectGetMaxY(rect));
} else {
newRect = CGRectMake(319 - (k * 1), 0, 1, CGRectGetMaxY(rect));
}
CGContextSaveGState(ctx);
//NO CLIPPING STATE
CGContextAddRect(ctx, newRect);
CGContextClip(ctx);
//CLIPPING STATE
CGContextDrawLinearGradient(
ctx,
gradient,
CGPointMake(0, 0),
CGPointMake(0, CGRectGetMaxY(rect)),
(CGGradientDrawingOptions)NULL);
CGContextRestoreGState(ctx);
//RESTORE TO NO CLIPPING STATE
CGGradientRelease(gradient);
}
//ANDROID - public void run() method on SurfaceView
for (i = 0; i < sonarData.arrayOfColorIntColumns.size() - currentPositionOffset; i++) {
Paint paint = new Paint();
int[] currentColors = sonarData.arrayOfColorIntColumns.get(currentPositionOffset + i);
//Log.d("currentColors.toString()",currentColors.toString());
LinearGradient linearGradient;
if (currentScaleFactor > 1.0) {
int numberOfColorsToUse = (int)(1000.0/currentScaleFactor);
int tmpTopOffset = currentTopOffset;
if (currentTopOffset + numberOfColorsToUse > 1000) {
//shift tmpTopOffset
tmpTopOffset = 1000 - numberOfColorsToUse - 1;
}
int[] subsetOfCurrentColors = new int[numberOfColorsToUse];
System.arraycopy(currentColors, tmpTopOffset, subsetOfCurrentColors, 0, numberOfColorsToUse);
linearGradient = new LinearGradient(0, tmpTopOffset, 0, getHeight(), subsetOfCurrentColors, null, Shader.TileMode.MIRROR);
//Log.d("getHeight()","" + getHeight());
//Log.d("subsetOfCurrentColors.length","" + subsetOfCurrentColors.length);
} else {
//use all colors
linearGradient = new LinearGradient(0, 0, 0, getHeight(), currentColors, null, Shader.TileMode.MIRROR);
//Log.d("getHeight()","" + getHeight());
//Log.d("currentColors.length","" + currentColors.length);
}
paint.setShader(linearGradient);
sonarData.checkAndAddPaint(paint);
numberOfColumnsToDraw = i + 1;
}
//Log.d(TAG,"numberOfColumnsToDraw " + numberOfColumnsToDraw);
currentPositionOffset = currentPositionOffset + i;
if (currentPositionOffset >= sonarData.getMaxNumberOfColumns()) {
currentPositionOffset = sonarData.getMaxNumberOfColumns() - 1;
}
if (numberOfColumnsToDraw > 0) {
Canvas canvas = surfaceHolder.lockCanvas();
if (AppInstanceData.sonarBackgroundImage != null && canvas != null) {
canvas.drawBitmap(AppInstanceData.sonarBackgroundImage, 0, getHeight()- AppInstanceData.sonarBackgroundImage.getHeight(), null);
if (cacheCanvas != null) {
cacheCanvas.drawBitmap(AppInstanceData.sonarBackgroundImage, 0, getHeight()- AppInstanceData.sonarBackgroundImage.getHeight(), null);
}
}
for (i = drawOffset; i < sizeToDraw + drawOffset; i++) {
Paint p = sonarData.paintArray.get(i - dataStartOffset);
p.setStrokeWidth(2);
//Log.d("drawGradientLines", "canvas.getHeight() " + canvas.getHeight());
canvas.drawLine(getWidth() - (i - drawOffset) * 2, 0, getWidth() - (i - drawOffset) * 2, canvas.getHeight(), p);
if (cacheCanvas != null) {
cacheCanvas.drawLine(getWidth() - (i - drawOffset) * 2, 0, getWidth() - (i - drawOffset) * 2, canvas.getHeight(), p);
}
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
No comment on the CG code — it's been a while since I've drawn any gradients — but a couple of notes:
You shouldn't be doing that in drawRect because it's called a lot. Draw into an image and display it.
There's no matching free for the malloc, so you're leaking memory like crazy.
It'll have a learning curve, but implement this using OpenGL ES 2.0. I previously took something that was drawing a large number of gradients as well, and reimplemented it using OpenGL ES 2.0 and custom vertex and fragment shaders. It is way faster than the equivalent drawing done using Core Graphics, so you will probably see a big speed boost as well.
If you don't know any OpenGL yet, I would suggest finding some tutorials for working with OpenGL ES 2.0 (has to be 2.0 because that's what offers the ability to write custom shaders) on iOS, to learn the basics. Once you do that, you should be able to significantly increase the performance of your drawing, way above that of the Android version, and maybe would be incentive to make the Android version use OpenGL as well.
I have a polygon that I fill using a texture and glDrawArray (using the method described in this tutorial: http://www.raywenderlich.com/32954/how-to-create-a-game-like-tiny-wings-with-cocos2d-2-x-part-1).
I want to be able to fill my polygon using a solid color, which is generated at random during gameplay. To do this using the technique from the tutorial, I need to dynamically create a texture that is just a solid color (for example, I might want to generate a 1x1 red square and use that to fill my polygons).
Is there a way to change the color of a texture in cocos2d, similar to how you would change the color of a sprite using [mySprite changeColor:ccRed]? So if I had my initial texture, say a 1x1 white square, is there a way I can change that texture to a 1x1 red square?
I have already tried using CCRenderTexture (as described in this tutorial: http://www.raywenderlich.com/33266/how-to-create-dynamic-textures-with-ccrendertexture-in-cocos2d-2-x) but, as I will be filling numerous polygons, this method proves to be quite slow.
I have also tried using the following code to create my texture:
// fill with solid red
GLubyte buffer[3] = {255, 0, 0};
CCTexture2D *texture = [[CCTexture2D alloc] initWithData:buffer pixelFormat:kCCTexture2DPixelFormat_RGB888 pixelsWide:1 pixelsHigh:1 contentSize:m];
While the above works fairly well, it is still slower than just grabbing the texture from a CCSprite. Basically, I am looking for a way to generate a dynamic texture as efficiently as possible.
Here is the code I am using to fill my polygons:
GLubyte buffer[3] = {arc4random()%256,arc4random()%256,arc4random()%256};
CGSize size;
size.width = 2; size.height = 2;
CCTexture2D *texture = [[CCTexture2D alloc] initWithData:buffer pixelFormat:kCCTexture2DPixelFormat_RGB888 pixelsWide:1 pixelsHigh:1 contentSize:size];
ccTexParams params = {GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT};
[texture setTexParameters:¶ms];
ccGLBindTexture2D([texture name]);
glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, array); //where array is an array of points defining a polygon
glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, array);
glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)4);
[texture dealloc];
Any help is appreciated.
Maybe what you are looking for is a mutable texture?
Here is a great blog post which utilizes CCMutableTextures http://www.cocos2d-iphone.org/pixel-based-destructible-ground-with-cocos2d/
Here is my open source project https://github.com/crebstar/PWNDestructibleTerrain
This is an open source project I've been working on over the Summer to create destructible terrain environments. The repo I just posted is without physics (soon to come), but provides an interface that wraps around mutable textures for sprites. It is fairly primitive as I started working on it a month ago, but it demonstrates how to use the CCMutableTexture class.
Around two or so years ago, Lam Hoang Pham released the CCMutableTexture class as open source. I built upon and around his library to provide more drawing utility and various other small features. The one caveat with using the CCMutableTexture class is you cannot use PVR's and must use a UIImage to provide the texture. I haven't noticed many performance issues with this method. The main problem would be you can't use a spritesheet.
Anyways here are some examples of how it is used:
// FROM THE GAME LAYER
[destTerrainSystem drawCircle:ccp(300,100) withRadius:30.0f withColor:ccc4(0, 0, 0, 0)];
[destTerrainSystem drawSquare:ccp(500,100) withRadius:30.0f withColor:ccc4(0, 0, 0, 0)];
// IN DESTTERRAIN
-(void) drawCircle:(CGPoint)circleOrigin withRadius:(float)radius withColor:(ccColor4B)color {
int localXOrigin = circleOrigin.x - self.position.x;
int localYOrigin = self.contentSize.height - (circleOrigin.y - self.position.y);
CCMutableTexture2D * terrainTexture = (CCMutableTexture2D *) [self texture];
[terrainTexture drawCircle:ccp(localXOrigin, localYOrigin) withRadius:radius withColor:color];
if ([delegate shouldApplyAfterEachDraw] || self.applyAfterDraw) [terrainTexture apply];
} // end drawCircle
-(void) drawSquare:(CGPoint)squareOrigin withRadius:(float)radius withColor:(ccColor4B)color {
int localXOrigin = squareOrigin.x - self.position.x;
int localYOrigin = self.contentSize.height - (squareOrigin.y - self.position.y);
CCMutableTexture2D * terrainTexture = (CCMutableTexture2D *) [self texture];
[terrainTexture drawSquare:ccp(localXOrigin, localYOrigin) withRadius:radius withColor:color];
if ([delegate shouldApplyAfterEachDraw] || self.applyAfterDraw)
[terrainTexture apply];
} // end drawSquare
// IN CCMUTABLETEXTURE
-(void) drawCircle:(CGPoint)circleOrigin withRadius:(float)radius withColor:(ccColor4B)color {
/*
Draws a circle. There is some overlap here but it is fairly efficient
*/
int x = radius;
int y = 0;
int radiusError = 1 - x;
while (x >= y) {
// Bottom half
[self drawHorizontalLine:(x + circleOrigin.x) :(circleOrigin.x - x) :(y + circleOrigin.y) withColor:color];
// Top half
[self drawHorizontalLine:(x + circleOrigin.x) :(circleOrigin.x - x) :(circleOrigin.y - y) withColor:color];
// left side
[self drawVerticalLine:(x + circleOrigin.y) endY:(circleOrigin.y - x) atX:(-y + circleOrigin.x) withColor:color];
// right side
[self drawVerticalLine:(x + circleOrigin.y) endY:(circleOrigin.y - x) atX:(y + circleOrigin.x) withColor:color];
y++;
if (radiusError < 0) {
radiusError = radiusError + ((2 * y) +1);
} else {
x--; // Comment this out to draw a square
radiusError = radiusError + (2 * (y - x + 1));
} // end if
} // end while
// Cache the altered col values
for (int col = circleOrigin.x - radius; col <= circleOrigin.x + radius; col++) {
if (col < 0 || col >= size_.width) continue;
[alteredColumns addObject:[NSNumber numberWithInt:col]];
} // end for
} // end draw circle
The CCMutableTexture maintains a model of the texture in an array of pixels (row major storage). You can then access, change, and poll for the property of each pixel. After you have modified the array, you can then apply the changes by calling apply. This allows for some flexibility and performance tweaking as apply can be an expensive call.
There is a lot more you can do... But this should be a good starting point. Both links have example code on how to use the CCMutableTexture.
Hope this helps
I am drawing a simple grid, and I want the line closest to the center of the screen to be highlighted a different color.
What is the formula to determine what line was drawn that closely resembles the center of the screen?
It doesn't have to be the exact center, just one that appears to be in the middle of the screen. But it must be a line that was drawn. The user can change the size of the grid at anytime, so this line must move with it.
I am drawing a new line on the screen using a different stroke color, but I can't determine which line to overlap. I can get close but I am always off by a few pixels.
Take a look at this picture in Photoshop. The green line represents the true center of the image. While the pink line is the desired result (center line) because the grid isn't even to the screen size (look at the last grid on the right) The grid is 34x34 and the screen size is 320 x 480.
How to draw the grid:
int xStart = 0, yStart = 0;
int gsX = 19; //Distance between lines
int gsY = 25;
// draw vertical lines
for(int xId=0; xId<=(screenWidth/gsX); xId++) {
int x = xStart + xId * gsX;
[gPath moveToPoint:CGPointMake(x, yStart)];
[gPath addLineToPoint:CGPointMake(x, yStart+screenHeight)];
}
// draw horizontal lines
for(int yId=0; yId<=(screenHeight/gsY); yId++) {
int y = yStart + yId * gsY;
[gPath moveToPoint:CGPointMake(xStart, y)];
[gPath addLineToPoint:CGPointMake(xStart+screenWidth, y)];
}
My centerline code:
This moves the line based upon the grid spacing value, but it isn't drawn over one of the lines near the center.
int x = (screenWidth/gsX) /2;
NSLog(#"New X: %i gsX: %i",x, gsX);
//Veritical
[centerLines moveToPoint:CGPointMake(x, 0)];
[centerLines addLineToPoint:CGPointMake(x, screenHeight)];
Actually every one is right. I ran into something similar not to long ago actually. I couldn't explain it but it felt like the order of operations wasn't being followed correctly. So I broke your equation down so that you can follow the order of the operations. Any way your solution is as followed.
int centerX = (screenWidth/gsX);
int tempA = ( centerX / 2 );
int tempB = tempA * gsX;
NSLog(#"screenwidth / gsX = %i", centerX);
NSLog(#"Temp A: %i ", tempA);
NSLog(#"Temp B: %i ", tempB);
//Veritical
[centerLines moveToPoint:CGPointMake(tempB, 0)];
[centerLines addLineToPoint:CGPointMake(tempB, screenHeight)];
Here's whats happening. You're already drawing this line at one point in your grid code. You just have to figure out which one it is.You know that screenWidth/gsX is the last "line that will be drawn. So that number divided by 2 is the middle line. It's already a factor of the screenSize. Then just multiply that number by how big your grid is. Since it is the 'middle line' closest to the center (screenWidth/gsX) your line should show up on top of the grid
That should always draw a middle line. I don't see any code where you are changing the color. So you will have to take it on blind faith that it is being drawn. If you can change your line color you should be able to see it.
I'll leave it to you to figure out horizontal. (hint: it deals with y value ;-) )
I hope this helps!
Have fun and good luck Mr. Bourne!
Center is
int centerX = ((screenWidth/2) / gsX )* gsX;
int centerY = ((screenHeight/2) / gsY ) * gsY;
Just make sure you are doing integer math above! no floats. It should work out fine.
int x = xStart + (screenWidth/gsX)/2 * gsX;
I'm using CGLayers to implement a "painting" technique similar to Photoshop airbrush - and have run into something strange. When I use transparency and overpaint an area, the color never reaches full intensity (if the alpha value is below 0.5). My application uses a circular "airbrush" pattern with opacity fall off at the edges but I have reproduced the problem just using a semi-transparent white square. When the opacity level is less than 0.5, the overpainted area never reaches the pure white of the source layer. I probably wouldn't have noticed but I'm using the result of the painting as a mask, and not being able to get pure white causes problems. Any ideas what's going on here? Target iOS SDK 5.1.
Below is the resultant color after drawing the semi-transparent square many times over black background:
opacity color
------ -----
1.0 255
0.9 255
0.8 255
0.7 255
0.6 255
0.5 255
0.4 254
0.3 253
0.2 252
0.1 247
Simplified code that shows the issue:
- (void)drawRect:(CGRect)rect
{
CGContextRef viewContext = UIGraphicsGetCurrentContext();
// Create grey gradient to compare final blend color
CGRect lineRect = CGRectMake(20, 20, 1, 400);
float greyLevel = 1.0;
for(int i=0;i<728;i++)
{
CGContextSetRGBFillColor(viewContext, greyLevel, greyLevel, greyLevel, 1);
CGContextFillRect(viewContext, lineRect);
lineRect.origin.x += 1;
greyLevel -= 0.0001;
}
// Create semi-transparent white square
CGSize whiteSquareSize = CGSizeMake(40, 40);
CGLayerRef whiteSquareLayer = CGLayerCreateWithContext (viewContext, whiteSquareSize, NULL);
CGContextRef whiteSquareContext = CGLayerGetContext(whiteSquareLayer);
CGContextSetAlpha(whiteSquareContext, 1.0f); // just to make sure
CGContextSetRGBFillColor(whiteSquareContext, 1, 1, 1, 0.3); // ??? color never reaches pure white if alpha < 0.5
CGRect whiteSquareRect = CGRectMake(0, 0, whiteSquareSize.width, whiteSquareSize.height);
CGContextFillRect(whiteSquareContext, whiteSquareRect);
// "Paint" with layer a bazillion times
CGContextSetBlendMode(viewContext, kCGBlendModeNormal); // just to make sure
CGContextSetAlpha(viewContext, 1.0); // just to make sure
for(int strokeNum=0;strokeNum<100;strokeNum++)
{
CGPoint drawPoint = CGPointMake(0, 400);
for(int x=0;x<730;x++)
{
CGContextDrawLayerAtPoint(viewContext, drawPoint, whiteSquareLayer);
drawPoint.x++;
}
}
}