Archiv der Kategorie ‘C‘

 
 

C Blocks as Arguments

I don’t know the details, but based off the little I’ve read online, Apple added the ability to point to C blocks. This means that you can do interesting stuff like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
 
void repeat(int num, void(^block)()){
	for (int i = 0; i < num; i++){
	  printf("--");
	  block();
	}
}
 
int main() {
 
	repeat(10, ^{
		static int i = 0;
		i++;
		printf("%d\n", i);
	});
 
	return 0;
}

This will output:

--1
--2
--3
--4
--5
--6
--7
--8
--9
--10

It’s common in jQuery to do things like:

thing.click(function(){
  alert("I was clicked");
});

Kind of interesting that you can do it in C too…

Based on googling, this works in osx 10.6 and with a little tweak of the compiler settings 10.5.

As a side note, this is doable pretty much across the board with function pointers – you just don’t have anonymous functions so you have to define a function and then pass it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
 
void runTen(void (*func)()){
	for(int i = 0; i < 10; i++)
		func();
}
void count(){
	static int i = 0;
	printf("--%d\n", ++i);	
}
 
int main(){
       // no need for &
	runTen(count);
	return 0;
}

I could still see using the block technique in certain scenarios – especially with some of the interesting things going on in Block.h like Block_copy() etc…

For more info check out this great explanation:

http://thirdcog.eu/pwcblocks/

Krink

Over the weekend and on monday I created an bunch of visual and non-visual C experiments. Here is one of the programs that came out particularly nicely. I’ve only bothered compiling it on OSX but it would be easy to port over to windows since it uses glut. You have a few choices for viewing:

Look at stills on flickr:

krinkScreen shot 2011-04-11 at 10.03.13 PMScreen shot 2011-04-11 at 10.15.35 PMScreen shot 2011-04-11 at 10.13.06 PMScreen shot 2011-04-11 at 10.11.18 PMScreen shot 2011-04-11 at 10.09.01 PMScreen shot 2011-04-11 at 10.08.21 PMScreen shot 2011-04-11 at 10.06.39 PMScreen shot 2011-04-11 at 10.06.00 PMScreen shot 2011-04-11 at 10.04.07 PMScreen shot 2011-04-11 at 10.03.41 PMScreen shot 2011-04-11 at 10.17.00 PMScreen shot 2011-04-11 at 10.15.47 PMScreen shot 2011-04-11 at 10.15.28 PMScreen shot 2011-04-11 at 10.14.57 PMScreen shot 2011-04-11 at 10.13.43 PMScreen shot 2011-04-11 at 10.08.01 PMScreen shot 2011-04-11 at 10.04.52 PMScreen shot 2011-04-11 at 9.49.16 PMScreen shot 2011-04-11 at 9.48.50 PM

Watch the short video:

Download the Application:

KrinkApp

Download the Xcode Project:

Krink

I don’t want to post all the code here since there are a few files and it would be kind of confusing – if you’d like to see all the code, download the Xcode project. I will highlight a few parts though:

Some code snippets:

Circle.h

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct Circle{
	float x;
	float y;
	float vx;
	float vy;
	float dist;
	Color *col;
	int id;
	void (*update)(struct Circle *c);
} Circle;
 
Circle makeCircle();
static void update(Circle *c);

The interesting thing here is the function pointer member of the struct. Later on in Circle.c we point all new Circle structs update member to Circle.c’s static update function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "main.h"
#include "Circle.h"
 
Circle makeCircle(){
 
	Circle c;
	c.x = rand() % width;
	c.y = rand() % height;
	c.vx = rnd() * 8 - 4;
	c.vy = rnd() * 8 - 4;
	c.dist = 10 + rnd() * 100;
	c.col = makeColor();
	c.update = update; 
	c.id = 0;
 
	return c;
}
 
static void update(Circle *c){
 
	c->x += c->vx;
	c->y += c->vy;
 
	if (c->x > width) c->vx *= -1, c->x = width;
	if (c->y > height) c->vy *= -1, c->y = height;
 
	if (c->x < 0) c->vx *= -1, c->x = 0;
	if (c->y < 0) c->vy *= -1, c->y = 0;
 
	glVertex2f(c->x , c->y);
}

Here’s a snippet from main.h:

1
2
3
4
5
6
7
8
typedef struct {
	float r;
	float g;
	float b;
	float a;
} Color;
 
extern Color *makeColor();

and then later in main.c we define makeColor():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Color *makeColor(){
	static Color colors[COLOR_NUM] =
	{{0.765, 0.902, 0.875, 0.2},
		{0.039, 0.059, 0.075, 0.2},
		{0.247, 0.251, 0.259, 0.2},
		{0.345, 0.514, 0.549, 0.2},
		{0.929, 0.878, 0.671, 0.2},
		{0.851, 0.965, 1.000, 0.2},
		{0.498, 0.247, 0.149, 0.2},
		{0.090, 0.098, 0.078, 0.2},
		{0.545, 0.584, 0.486, 0.2},
		{0.157, 0.180, 0.133, 0.2}};
 
	return &colors[rand() % COLOR_NUM];
}

For some reason I decided to encapsulate all the colors into a function that would then spit out a pointer to a random value in the static colors array – so there are only every COLOR_NUM color struct instances no matter how many particles (Circle struct instances) there are. Lots of other ways to do this same thing I guess… I got the colors from my drawings, I speed coded a little AS3 to grab a few random values from a given MovieClip and write the struct initializations. The actionscript is funny because I coded it javascript style for some reason:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var panel = addChild(new Sprite());
 
var bit = new BitmapData(sample.width, sample.height, false, 0);
 
bit.draw(sample);
 
var cols;
 
stage.addEventListener(MouseEvent.CLICK, function(){
	cols = "{";
	for (var i = 0; i<10; i++){
		var c = bit.getPixel(int(Math.random() * sample.width), 
							 int(Math.random() * sample.height));
		cols += toArray(c);
		panel.graphics.beginFill(c);
		panel.graphics.drawRect(0, i * 20, 20, 20);
	}
	cols = cols.substr(0,cols.length-2) + "};";
	trace(cols);
});
 
var alph = 0.2;
function toArray(c){
	var r = (c >> 16) & 0xFF;
	r /= 0xFF;
	var g = (c >> 8) & 0xFF;
	g /= 0xFF;
	var b = c & 0xFF;
	b /= 0xFF;
	return "{"+r.toFixed(3)+", "+g.toFixed(3)+", "+b.toFixed(3)+", " + alph + "},\n";
}

C Glut OpenGL & Xcode Project

Two people asked me about OpenGL C and Xcode this last week. So I figured I’d make a quick video to show an easy way to get up and running.

Little Mistake
Note that you should change the Active Architecture of your project to i386. I forgot to do that in the video. It will still work if you don’t do this, but you’ll get some loading errors in the console… so, make this change after you’ve watched the video:

The first 3 minutes of this video show everything you need to know, the next 7 minutes is just me sort of rambling about a few things that you may or may not need to know, so feel free to just watch the first 3 minutes and then go and code some OpenGL.


Source for template is at bottom of post.

Links:
Red Book
stdlib.h
vbl sync

Here is the source for the 2D template, once you’ve got your project set up, just copy it into main.c and compile.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
 
#include <GLUT/glut.h>
#include <OpenGL/OpenGL.h>
 
int mouseX = 0;
int mouseY = 0;
int width;
int height;
 
void init(){
	glPointSize(60.0);
}
 
void render() {
	//glClear(GL_COLOR_BUFFER_BIT);	
 
	glColor4f(1, 1, 1, 0.5);
	glBegin(GL_POINTS);
	glVertex2i(mouseX, mouseY);
	glEnd();
 
	// you need this (see double buffering)
	glutSwapBuffers();
}
 
void resize(int w, int h) {
	glClear(GL_COLOR_BUFFER_BIT);
	width = w;
	height = h;
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);  
	glLoadIdentity();            
	glOrtho(0, w, 0, h, -1, 1);   
	glScalef(1, -1, 1);         
	glTranslatef(0, -h, 0);
}
 
void idle() {
	glutPostRedisplay();
}
 
void mouse(int x, int y){
	mouseX = x;
	mouseY = y;
}
 
int main(int argc, char** argv){
 
	glutInit(&argc, argv);
 
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
 
	width = 640;
	height = 480;
	glutInitWindowSize(width, height);
	glutCreateWindow("Template");
	//glutFullScreen();
	//glutSetCursor(GLUT_CURSOR_NONE); 
 
	glutPassiveMotionFunc(mouse);
	glutDisplayFunc(render);
	glutReshapeFunc(resize);
	glutIdleFunc(idle);
 
	glEnable(GL_BLEND);	
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glDisable(GL_DEPTH_TEST);
 
	glEnable(GL_POINT_SMOOTH);
	glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
 
	// VBL synching prevent tearing
	GLint sync = 1;
	CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &sync);
 
	init();
 
	glutMainLoop();
 
	return EXIT_SUCCESS;
}