rayfract

changeset 0:09bb67c000bc

ray-fract repository
author John Tsiombikas <nuclear@siggraph.org>
date Thu, 21 Oct 2010 23:39:26 +0300
parents
children 03022062c464
files Makefile sdr/julia.p.glsl sdr/sdr.v.glsl src/rayfract.cc src/sdr.c src/sdr.h
diffstat 6 files changed, 981 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Makefile	Thu Oct 21 23:39:26 2010 +0300
     1.3 @@ -0,0 +1,23 @@
     1.4 +csrc = $(wildcard src/*.c)
     1.5 +ccsrc = $(wildcard src/*.cc)
     1.6 +obj = $(ccsrc:.cc=.o) $(csrc:.c=.o)
     1.7 +bin = rayfract
     1.8 +
     1.9 +ifeq ($(shell uname -s), Darwin)
    1.10 +	libgl = -framework OpenGL -framework GLUT -lGLEW
    1.11 +else
    1.12 +	libgl = -lGL -lglut -lGLEW
    1.13 +endif
    1.14 +
    1.15 +CC = gcc
    1.16 +CXX = g++
    1.17 +CFLAGS = -pedantic -Wall -g `pkg-config --cflags vmath`
    1.18 +CXXFLAGS = -pedantic -Wall -g `pkg-config --cflags vmath`
    1.19 +LDFLAGS = $(libgl) `pkg-config --libs vmath`
    1.20 +
    1.21 +$(bin): $(obj)
    1.22 +	$(CXX) -o $@ $(obj) $(LDFLAGS)
    1.23 +
    1.24 +.PHONY: clean
    1.25 +clean:
    1.26 +	rm -f $(obj) $(bin)
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/sdr/julia.p.glsl	Thu Oct 21 23:39:26 2010 +0300
     2.3 @@ -0,0 +1,289 @@
     2.4 +/* vim: set ft=glsl:ts=4:sw=4 */
     2.5 +uniform vec4 seed;
     2.6 +uniform sampler2D ray_tex;
     2.7 +uniform float err_thres;
     2.8 +uniform int iter;
     2.9 +
    2.10 +#define quat(s, x, y, z)	vec4(x, y, z, s)
    2.11 +#define quat_identity()		vec4(0.0, 0.0, 0.0, 1.0)
    2.12 +
    2.13 +#define vec2quat(v)		(v).wxyz
    2.14 +
    2.15 +struct Ray {
    2.16 +	vec3 origin;
    2.17 +	vec3 dir;
    2.18 +};
    2.19 +
    2.20 +struct Julia {
    2.21 +	bool inside;
    2.22 +	vec4 q;
    2.23 +	vec4 qprime;
    2.24 +};
    2.25 +
    2.26 +struct ISect {
    2.27 +	bool hit;
    2.28 +	float t;
    2.29 +	vec3 pos;
    2.30 +	vec3 normal;
    2.31 +	vec3 color;
    2.32 +	float kr;
    2.33 +};
    2.34 +
    2.35 +ISect find_intersection(Ray ray);
    2.36 +vec3 shade(Ray ray, ISect isect);
    2.37 +float amboc(ISect isect);
    2.38 +vec3 sky(Ray ray);
    2.39 +Julia julia(vec4 q, vec4 c);
    2.40 +float julia_dist(vec4 z);
    2.41 +vec3 julia_grad(vec4 z);
    2.42 +vec4 quat_mul(vec4 q1, vec4 q2);
    2.43 +vec4 quat_sq(vec4 q);
    2.44 +float quat_length_sq(vec4 q);
    2.45 +ISect ray_julia(Ray ray);
    2.46 +ISect ray_sphere(Ray ray, float rad);
    2.47 +ISect ray_floor(Ray ray);
    2.48 +Ray get_primary_ray();
    2.49 +
    2.50 +
    2.51 +void main()
    2.52 +{
    2.53 +	Ray ray = get_primary_ray();
    2.54 +
    2.55 +	float energy = 1.0;
    2.56 +	vec3 color = vec3(0.0, 0.0, 0.0);
    2.57 +
    2.58 +	while(energy > 0.001) {
    2.59 +		ISect res = find_intersection(ray);
    2.60 +
    2.61 +		if(res.hit) {
    2.62 +			color += shade(ray, res) * energy;
    2.63 +			energy *= res.kr;
    2.64 +
    2.65 +			ray.origin = res.pos;
    2.66 +			ray.dir = reflect(ray.dir, res.normal);
    2.67 +		} else {
    2.68 +			color += sky(ray) * energy;
    2.69 +			break;
    2.70 +		}
    2.71 +	}
    2.72 +
    2.73 +	gl_FragColor = vec4(color, 1.0);
    2.74 +}
    2.75 +
    2.76 +
    2.77 +ISect find_intersection(Ray ray)
    2.78 +{
    2.79 +	ISect res;
    2.80 +	res.hit = false;
    2.81 +	
    2.82 +	ISect bhit = ray_sphere(ray, 2.0);
    2.83 +	if(bhit.hit) {
    2.84 +		ray.origin = bhit.pos;
    2.85 +		res = ray_julia(ray);
    2.86 +	}
    2.87 +
    2.88 +	if(!res.hit) {
    2.89 +		res = ray_floor(ray);
    2.90 +	}
    2.91 +	return res;
    2.92 +}
    2.93 +
    2.94 +vec3 shade(Ray ray, ISect isect)
    2.95 +{
    2.96 +	vec3 ldir = normalize(vec3(10.0, 10.0, -10.0) - isect.pos);
    2.97 +	vec3 vdir = -ray.dir;
    2.98 +	vec3 hdir = normalize(ldir + vdir);
    2.99 +
   2.100 +	float ndotl = dot(ldir, isect.normal);
   2.101 +	float ndoth = dot(hdir, isect.normal);
   2.102 +
   2.103 +	vec3 dcol = /*isect.color * max(ndotl, 0.0) */ amboc(isect);
   2.104 +	vec3 scol = vec3(1.0, 1.0, 1.0) * pow(max(ndoth, 0.0), 40.0);
   2.105 +
   2.106 +	return /*vec3(0.05, 0.05, 0.05) + */dcol;// + scol;
   2.107 +}
   2.108 +
   2.109 +#define AO_STEP		0.04
   2.110 +#define AO_MAGIC	8.0
   2.111 +float amboc(ISect isect)
   2.112 +{
   2.113 +	float sum = 0.0;
   2.114 +
   2.115 +	for(float fi=0.0; fi<5.0; fi+=1.0) {
   2.116 +		float sample_dist = fi * AO_STEP;
   2.117 +		vec3 pt = isect.pos + isect.normal * sample_dist;
   2.118 +		float jdist = julia_dist(quat(pt.x, pt.y, pt.z, 0.0));
   2.119 +
   2.120 +		sum += 1.0 / pow(2.0, fi) * (sample_dist - jdist);
   2.121 +	}
   2.122 +	
   2.123 +	return 1.0 - AO_MAGIC * sum;
   2.124 +}
   2.125 +
   2.126 +vec3 sky(Ray ray)
   2.127 +{
   2.128 +	vec3 col1 = vec3(0.75, 0.78, 0.8);
   2.129 +	vec3 col2 = vec3(0.56, 0.7, 1.0);
   2.130 +
   2.131 +	float t = max(ray.dir.y, -0.5);
   2.132 +	return mix(col1, col2, t);
   2.133 +}
   2.134 +
   2.135 +Julia julia(vec4 q, vec4 c)
   2.136 +{
   2.137 +	Julia res;
   2.138 +	res.inside = true;
   2.139 +
   2.140 +	res.q = q;
   2.141 +	res.qprime = quat_identity();
   2.142 +
   2.143 +	for(int i=0; i<iter; i++) {
   2.144 +		res.qprime = 2.0 * quat_mul(res.q, res.qprime);
   2.145 +		res.q = quat_sq(res.q) + c;
   2.146 +
   2.147 +		if(dot(res.q, res.q) > 8.0) {
   2.148 +			res.inside = false;
   2.149 +			break;
   2.150 +		}
   2.151 +	}
   2.152 +	return res;
   2.153 +}
   2.154 +
   2.155 +float julia_dist(vec4 z)
   2.156 +{
   2.157 +	Julia jres = julia(z, seed);
   2.158 +
   2.159 +	float lenq = length(jres.q);
   2.160 +	float lenqprime = length(jres.qprime);
   2.161 +
   2.162 +	return 0.5 * lenq * log(lenq) / lenqprime;
   2.163 +}
   2.164 +
   2.165 +#define OFFS 1e-4
   2.166 +vec3 julia_grad(vec4 z)
   2.167 +{
   2.168 +	vec3 grad;
   2.169 +	grad.x = julia_dist(z + quat(OFFS, 0.0, 0.0, 0.0)) - julia_dist(z - quat(OFFS, 0.0, 0.0, 0.0));
   2.170 +	grad.y = julia_dist(z + quat(0.0, OFFS, 0.0, 0.0)) - julia_dist(z - quat(0.0, OFFS, 0.0, 0.0));
   2.171 +	grad.z = julia_dist(z + quat(0.0, 0.0, OFFS, 0.0)) - julia_dist(z - quat(0.0, 0.0, OFFS, 0.0));
   2.172 +	return grad;
   2.173 +}
   2.174 +
   2.175 +vec4 quat_mul(vec4 q1, vec4 q2)
   2.176 +{
   2.177 +	vec4 res;
   2.178 +	res.w = q1.w * q2.w - dot(q1.xyz, q2.xyz);
   2.179 +	res.xyz = q1.w * q2.xyz + q2.w * q1.xyz + cross(q1.xyz, q2.xyz);
   2.180 +	return res;
   2.181 +}
   2.182 +
   2.183 +vec4 quat_sq(vec4 q)
   2.184 +{
   2.185 +	vec4 res;
   2.186 +	res.w = q.w * q.w - dot(q.xyz, q.xyz);
   2.187 +	res.xyz = 2.0 * q.w * q.xyz;
   2.188 +	return res;
   2.189 +}
   2.190 +
   2.191 +ISect ray_julia(Ray inray)
   2.192 +{
   2.193 +	float dist_acc = 0.0;
   2.194 +	Ray ray = inray;
   2.195 +	ISect res;
   2.196 +
   2.197 +	for(float fi=0.0; ; fi+=0.1) {
   2.198 +		vec4 q = quat(ray.origin.x, ray.origin.y, ray.origin.z, 0.0);
   2.199 +		
   2.200 +		float dist = julia_dist(q);
   2.201 +
   2.202 +		ray.origin += ray.dir * dist;
   2.203 +		dist_acc += dist;
   2.204 +
   2.205 +		if(dist < err_thres) {
   2.206 +			res.hit = true;
   2.207 +			res.t = dist_acc;
   2.208 +			res.pos = ray.origin;
   2.209 +			res.normal = normalize(julia_grad(quat(res.pos.x, res.pos.y, res.pos.z, 0.0)));
   2.210 +			res.color = vec3(0.75, 0.8, 0.9);//abs(res.normal) * 0.2;
   2.211 +			//res.kr = 0.6;
   2.212 +			res.kr = 0.0;
   2.213 +			break;
   2.214 +		}
   2.215 +
   2.216 +		if(dot(ray.origin, ray.origin) > 100.0) {
   2.217 +			res.hit = false;
   2.218 +			break;
   2.219 +		}
   2.220 +	}
   2.221 +
   2.222 +	return res;
   2.223 +}
   2.224 +
   2.225 +ISect ray_sphere(Ray ray, float rad)
   2.226 +{
   2.227 +	ISect res;
   2.228 +	res.hit = false;
   2.229 +
   2.230 +	float a = dot(ray.dir, ray.dir);
   2.231 +	float b = 2.0 * dot(ray.dir, ray.origin);
   2.232 +	float c = dot(ray.origin, ray.origin) - rad * rad;
   2.233 +
   2.234 +	float d = b * b - 4.0 * a * c;
   2.235 +	if(d < 0.0) return res;
   2.236 +
   2.237 +	float sqrt_d = sqrt(d);
   2.238 +	float t1 = (-b + sqrt_d) / (2.0 * a);
   2.239 +	float t2 = (-b - sqrt_d) / (2.0 * a);
   2.240 +
   2.241 +	if((t1 >= 0.0 || t2 >= 0.0)) {
   2.242 +		if(t1 < 0.0) t1 = t2;
   2.243 +		if(t2 < 0.0) t2 = t1;
   2.244 +		
   2.245 +		res.hit = true;
   2.246 +		res.t = min(t1, t2);
   2.247 +		res.pos = ray.origin + ray.dir * res.t;
   2.248 +		res.color = vec3(1.0, 0.3, 0.2);
   2.249 +		res.normal = res.pos / rad;
   2.250 +	}
   2.251 +
   2.252 +	return res;
   2.253 +}
   2.254 +
   2.255 +#define FLOOR_HEIGHT	(-2.0)
   2.256 +
   2.257 +ISect ray_floor(Ray ray)
   2.258 +{
   2.259 +	ISect res;
   2.260 +	res.hit = false;
   2.261 +
   2.262 +	if(ray.origin.y < FLOOR_HEIGHT || ray.dir.y >= 0.0) {
   2.263 +		return res;
   2.264 +	}
   2.265 +
   2.266 +	res.normal = vec3(0.0, 1.0, 0.0);
   2.267 +	float ndotdir = dot(res.normal, ray.dir);
   2.268 +
   2.269 +	float t = (FLOOR_HEIGHT - ray.origin.y) / ndotdir;
   2.270 +	res.pos = ray.origin + ray.dir * t;
   2.271 +
   2.272 +	if(abs(res.pos.x) > 8.0 || abs(res.pos.z) > 8.0) {
   2.273 +		res.hit = false;
   2.274 +	} else {
   2.275 +		res.hit = true;
   2.276 +	
   2.277 +		float chess = mod(floor(res.pos.x) + floor(res.pos.z), 2.0);
   2.278 +		res.color = mix(vec3(0.498, 0.165, 0.149), vec3(0.776, 0.851, 0.847), chess);
   2.279 +		res.kr = 0.0;
   2.280 +	}
   2.281 +	return res;
   2.282 +}
   2.283 +
   2.284 +Ray get_primary_ray()
   2.285 +{
   2.286 +	Ray ray;
   2.287 +	vec2 tc = gl_TexCoord[0].xy;
   2.288 +	ray.dir = gl_NormalMatrix * normalize(texture2D(ray_tex, tc).xyz);
   2.289 +	ray.origin = (gl_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
   2.290 +	return ray;
   2.291 +}
   2.292 +
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/sdr/sdr.v.glsl	Thu Oct 21 23:39:26 2010 +0300
     3.3 @@ -0,0 +1,5 @@
     3.4 +void main()
     3.5 +{
     3.6 +	gl_Position = gl_Vertex;
     3.7 +	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
     3.8 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/rayfract.cc	Thu Oct 21 23:39:26 2010 +0300
     4.3 @@ -0,0 +1,293 @@
     4.4 +#include <stdio.h>
     4.5 +#include <stdlib.h>
     4.6 +#include <assert.h>
     4.7 +#include <GL/glew.h>
     4.8 +#include <GL/glut.h>
     4.9 +#include <vmath.h>
    4.10 +#include "sdr.h"
    4.11 +
    4.12 +void disp();
    4.13 +void reshape(int x, int y);
    4.14 +void keyb(unsigned char key, int x, int y);
    4.15 +void mouse(int bn, int state, int x, int y);
    4.16 +void motion(int x, int y);
    4.17 +
    4.18 +int load_shader();
    4.19 +unsigned int create_ray_texture(int xsz, int ysz, float vfov, Vector2 *tex_scale = 0);
    4.20 +static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg);
    4.21 +static int round_pow2(int x);
    4.22 +
    4.23 +float cam_theta = 0, cam_phi = 0, cam_dist = 4.0;
    4.24 +float cam_y = 0;
    4.25 +
    4.26 +unsigned int sdr;
    4.27 +unsigned int ray_tex;
    4.28 +Vector2 tex_scale;
    4.29 +Vector4 seed;
    4.30 +float err_thres = 0.0075;
    4.31 +int iter = 10;
    4.32 +
    4.33 +int main(int argc, char **argv)
    4.34 +{
    4.35 +	int xsz, ysz;
    4.36 +
    4.37 +	seed = Vector4(0.4, 0.0, 0.0, -0.8);
    4.38 +
    4.39 +	glutInitWindowSize(640, 480);
    4.40 +	glutInit(&argc, argv);
    4.41 +	glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
    4.42 +	glutCreateWindow("Raytraced Fractals");
    4.43 +	xsz = glutGet(GLUT_WINDOW_WIDTH);
    4.44 +	ysz = glutGet(GLUT_WINDOW_HEIGHT);
    4.45 +
    4.46 +	glutDisplayFunc(disp);
    4.47 +	glutReshapeFunc(reshape);
    4.48 +	glutKeyboardFunc(keyb);
    4.49 +	glutMouseFunc(mouse);
    4.50 +	glutMotionFunc(motion);
    4.51 +
    4.52 +	glEnable(GL_DEPTH_TEST);
    4.53 +	glEnable(GL_LIGHTING);
    4.54 +	glEnable(GL_LIGHT0);
    4.55 +	glEnable(GL_CULL_FACE);
    4.56 +
    4.57 +	glewInit();
    4.58 +
    4.59 +	if(load_shader() == -1) {
    4.60 +		return 1;
    4.61 +	}
    4.62 +
    4.63 +	glutMainLoop();
    4.64 +	return 0;
    4.65 +}
    4.66 +
    4.67 +int load_shader()
    4.68 +{
    4.69 +	if(sdr) {
    4.70 +		free_program(sdr);
    4.71 +	}
    4.72 +
    4.73 +	if(!(sdr = create_program_load("sdr/sdr.v.glsl", "sdr/julia.p.glsl"))) {
    4.74 +		return -1;
    4.75 +	}
    4.76 +	set_uniform_float4(sdr, "seed", seed.x, seed.y, seed.z, seed.w);
    4.77 +	set_uniform_float(sdr, "err_thres", err_thres);
    4.78 +	set_uniform_int(sdr, "iter", iter);
    4.79 +	return 0;
    4.80 +}
    4.81 +
    4.82 +void disp()
    4.83 +{
    4.84 +	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    4.85 +
    4.86 +	glMatrixMode(GL_MODELVIEW);
    4.87 +	glLoadIdentity();
    4.88 +	glRotatef(cam_theta, 0, 1, 0);
    4.89 +	glRotatef(cam_phi, 1, 0, 0);
    4.90 +	glTranslatef(0, 0, -cam_dist);
    4.91 +
    4.92 +	float lpos[] = {-1, 1, 3, 0};
    4.93 +	glLightfv(GL_LIGHT0, GL_POSITION, lpos);
    4.94 +
    4.95 +
    4.96 +	glMatrixMode(GL_TEXTURE);
    4.97 +	glPushMatrix();
    4.98 +	glScalef(tex_scale.x, tex_scale.y, 1.0);
    4.99 +
   4.100 +	glBindTexture(GL_TEXTURE_2D, ray_tex);
   4.101 +	glEnable(GL_TEXTURE_2D);
   4.102 +	bind_program(sdr);
   4.103 +
   4.104 +	glBegin(GL_QUADS);
   4.105 +	glColor3f(1, 1, 1);
   4.106 +	glTexCoord2f(0, 1); glVertex2f(-1, -1);
   4.107 +	glTexCoord2f(1, 1); glVertex2f(1, -1);
   4.108 +	glTexCoord2f(1, 0); glVertex2f(1, 1);
   4.109 +	glTexCoord2f(0, 0); glVertex2f(-1, 1);
   4.110 +	glEnd();
   4.111 +
   4.112 +	bind_program(0);
   4.113 +	glDisable(GL_TEXTURE_2D);
   4.114 +
   4.115 +	glMatrixMode(GL_TEXTURE);
   4.116 +	glPopMatrix();
   4.117 +
   4.118 +	glutSwapBuffers();
   4.119 +	assert(glGetError() == GL_NO_ERROR);
   4.120 +}
   4.121 +
   4.122 +void reshape(int x, int y)
   4.123 +{
   4.124 +	glViewport(0, 0, x, y);
   4.125 +	glMatrixMode(GL_PROJECTION);
   4.126 +	glLoadIdentity();
   4.127 +	gluPerspective(45.0, (float)x / (float)y, 1.0, 1000.0);
   4.128 +
   4.129 +	if(ray_tex) {
   4.130 +		glDeleteTextures(1, &ray_tex);
   4.131 +	}
   4.132 +	ray_tex = create_ray_texture(x, y, 50.0, &tex_scale);
   4.133 +}
   4.134 +
   4.135 +
   4.136 +void keyb(unsigned char key, int x, int y)
   4.137 +{
   4.138 +	switch(key) {
   4.139 +	case 27:
   4.140 +		exit(0);
   4.141 +
   4.142 +	case '-':
   4.143 +		if(iter > 1) {
   4.144 +			iter--;
   4.145 +			set_uniform_int(sdr, "iter", iter);
   4.146 +			printf("iter: %d\n", iter);
   4.147 +			glutPostRedisplay();
   4.148 +		}
   4.149 +		break;
   4.150 +
   4.151 +	case '=':
   4.152 +		iter++;
   4.153 +		set_uniform_int(sdr, "iter", iter);
   4.154 +		printf("iter: %d\n", iter);
   4.155 +		glutPostRedisplay();
   4.156 +		break;
   4.157 +
   4.158 +	case ',':
   4.159 +		err_thres -= 0.001;
   4.160 +		set_uniform_float(sdr, "err_thres", err_thres);
   4.161 +		printf("maximum error: %f\n", err_thres);
   4.162 +		glutPostRedisplay();
   4.163 +		break;
   4.164 +
   4.165 +	case '.':
   4.166 +		err_thres += 0.001;
   4.167 +		set_uniform_float(sdr, "err_thres", err_thres);
   4.168 +		printf("maximum error: %f\n", err_thres);
   4.169 +		glutPostRedisplay();
   4.170 +		break;
   4.171 +
   4.172 +	case 's':
   4.173 +		load_shader();
   4.174 +		glutPostRedisplay();
   4.175 +		break;
   4.176 +	}
   4.177 +}
   4.178 +
   4.179 +int bnstate[16];
   4.180 +
   4.181 +int prev_x = -1, prev_y;
   4.182 +void mouse(int bn, int state, int x, int y)
   4.183 +{
   4.184 +	bnstate[bn] = state == GLUT_DOWN ? 1 : 0;
   4.185 +	if(state == GLUT_DOWN) {
   4.186 +		if(bn == 3) {
   4.187 +			cam_dist -= 0.1;
   4.188 +			glutPostRedisplay();
   4.189 +			if(cam_dist < 0) cam_dist = 0;
   4.190 +		} else if(bn == 4) {
   4.191 +			cam_dist += 0.1;
   4.192 +			glutPostRedisplay();
   4.193 +		} else {
   4.194 +			prev_x = x;
   4.195 +			prev_y = y;
   4.196 +		}
   4.197 +	} else {
   4.198 +		prev_x = -1;
   4.199 +	}
   4.200 +}
   4.201 +
   4.202 +void motion(int x, int y)
   4.203 +{
   4.204 +	if(bnstate[0]) {
   4.205 +		cam_theta += (x - prev_x) * 0.5;
   4.206 +		cam_phi += (y - prev_y) * 0.5;
   4.207 +
   4.208 +		if(cam_phi < -90) cam_phi = -90;
   4.209 +		if(cam_phi > 90) cam_phi = 90;
   4.210 +
   4.211 +		glutPostRedisplay();
   4.212 +	}
   4.213 +
   4.214 +	if(bnstate[1]) {
   4.215 +		cam_y += (y - prev_y) * 0.1;
   4.216 +		glutPostRedisplay();
   4.217 +	}
   4.218 +
   4.219 +	if(bnstate[2]) {
   4.220 +		cam_dist += (y - prev_y) * 0.1;
   4.221 +		glutPostRedisplay();
   4.222 +	}
   4.223 +
   4.224 +	prev_x = x;
   4.225 +	prev_y = y;
   4.226 +}
   4.227 +
   4.228 +unsigned int create_ray_texture(int xsz, int ysz, float vfov, Vector2 *tex_scale)
   4.229 +{
   4.230 +	unsigned int tex;
   4.231 +	int tex_xsz = round_pow2(xsz);
   4.232 +	int tex_ysz = round_pow2(ysz);
   4.233 +	float *teximg, *dir;
   4.234 +
   4.235 +	teximg = new float[3 * tex_xsz * tex_ysz];
   4.236 +	dir = teximg;
   4.237 +
   4.238 +	for(int i=0; i<tex_ysz; i++) {
   4.239 +		for(int j=0; j<tex_xsz; j++) {
   4.240 +			if(j < xsz && i < ysz) {
   4.241 +				Vector3 rdir = get_primary_ray_dir(j, i, xsz, ysz, vfov);
   4.242 +				dir[0] = rdir.x;
   4.243 +				dir[1] = rdir.y;
   4.244 +				dir[2] = rdir.z;
   4.245 +			} else {
   4.246 +				dir[0] = dir[1] = 0.0f;
   4.247 +				dir[2] = 1.0f;
   4.248 +			}
   4.249 +
   4.250 +			dir += 3;
   4.251 +		}
   4.252 +	}
   4.253 +
   4.254 +	glGenTextures(1, &tex);
   4.255 +	glBindTexture(GL_TEXTURE_2D, tex);
   4.256 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   4.257 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   4.258 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
   4.259 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
   4.260 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F_ARB, tex_xsz, tex_ysz, 0, GL_RGB, GL_FLOAT, teximg);
   4.261 +	delete [] teximg;
   4.262 +
   4.263 +	if(tex_scale) {
   4.264 +		tex_scale->x = (float)xsz / (float)tex_xsz;
   4.265 +		tex_scale->y = (float)ysz / (float)tex_ysz;
   4.266 +	}
   4.267 +	return tex;
   4.268 +}
   4.269 +
   4.270 +static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg)
   4.271 +{
   4.272 +	float vfov = M_PI * vfov_deg / 180.0;
   4.273 +	float aspect = (float)w / (float)h;
   4.274 +
   4.275 +	float ysz = 2.0;
   4.276 +	float xsz = aspect * ysz;
   4.277 +
   4.278 +	float px = ((float)x / (float)w) * xsz - xsz / 2.0;
   4.279 +	float py = 1.0 - ((float)y / (float)h) * ysz;
   4.280 +	float pz = 1.0 / tan(0.5 * vfov);
   4.281 +
   4.282 +	float mag = sqrt(px * px + py * py + pz * pz);
   4.283 +
   4.284 +	return Vector3(px / mag, py / mag, pz / mag);
   4.285 +}
   4.286 +
   4.287 +static int round_pow2(int x)
   4.288 +{
   4.289 +	x--;
   4.290 +	x = (x >> 1) | x;
   4.291 +	x = (x >> 2) | x;
   4.292 +	x = (x >> 4) | x;
   4.293 +	x = (x >> 8) | x;
   4.294 +	x = (x >> 16) | x;
   4.295 +	return x + 1;
   4.296 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/sdr.c	Thu Oct 21 23:39:26 2010 +0300
     5.3 @@ -0,0 +1,324 @@
     5.4 +#include <stdio.h>
     5.5 +#include <stdlib.h>
     5.6 +#include <string.h>
     5.7 +#include <errno.h>
     5.8 +#include <assert.h>
     5.9 +#include <GL/glew.h>
    5.10 +
    5.11 +#if defined(unix) || defined(__unix__)
    5.12 +#include <unistd.h>
    5.13 +#include <sys/stat.h>
    5.14 +#endif	/* unix */
    5.15 +
    5.16 +#include "sdr.h"
    5.17 +
    5.18 +unsigned int create_vertex_shader(const char *src)
    5.19 +{
    5.20 +	return create_shader(src, GL_VERTEX_SHADER);
    5.21 +}
    5.22 +
    5.23 +unsigned int create_pixel_shader(const char *src)
    5.24 +{
    5.25 +	return create_shader(src, GL_FRAGMENT_SHADER);
    5.26 +}
    5.27 +
    5.28 +unsigned int create_shader(const char *src, unsigned int sdr_type)
    5.29 +{
    5.30 +	unsigned int sdr;
    5.31 +	int success, info_len;
    5.32 +	char *info_str = 0;
    5.33 +	GLenum err;
    5.34 +
    5.35 +	sdr = glCreateShader(sdr_type);
    5.36 +	assert(glGetError() == GL_NO_ERROR);
    5.37 +	glShaderSource(sdr, 1, &src, 0);
    5.38 +	err = glGetError();
    5.39 +	assert(err == GL_NO_ERROR);
    5.40 +	glCompileShader(sdr);
    5.41 +	assert(glGetError() == GL_NO_ERROR);
    5.42 +
    5.43 +	glGetShaderiv(sdr, GL_COMPILE_STATUS, &success);
    5.44 +	assert(glGetError() == GL_NO_ERROR);
    5.45 +	glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
    5.46 +	assert(glGetError() == GL_NO_ERROR);
    5.47 +
    5.48 +	if(info_len) {
    5.49 +		if((info_str = malloc(info_len + 1))) {
    5.50 +			glGetShaderInfoLog(sdr, info_len, 0, info_str);
    5.51 +			assert(glGetError() == GL_NO_ERROR);
    5.52 +		}
    5.53 +	}
    5.54 +
    5.55 +	if(success) {
    5.56 +		fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str);
    5.57 +	} else {
    5.58 +		fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str);
    5.59 +		glDeleteShader(sdr);
    5.60 +		sdr = 0;
    5.61 +	}
    5.62 +
    5.63 +	free(info_str);
    5.64 +	return sdr;
    5.65 +}
    5.66 +
    5.67 +void free_shader(unsigned int sdr)
    5.68 +{
    5.69 +	glDeleteShader(sdr);
    5.70 +}
    5.71 +
    5.72 +unsigned int load_vertex_shader(const char *fname)
    5.73 +{
    5.74 +	return load_shader(fname, GL_VERTEX_SHADER);
    5.75 +}
    5.76 +
    5.77 +unsigned int load_pixel_shader(const char *fname)
    5.78 +{
    5.79 +	return load_shader(fname, GL_FRAGMENT_SHADER);
    5.80 +}
    5.81 +
    5.82 +unsigned int load_shader(const char *fname, unsigned int sdr_type)
    5.83 +{
    5.84 +#if defined(unix) || defined(__unix__)
    5.85 +	struct stat st;
    5.86 +#endif
    5.87 +	unsigned int sdr;
    5.88 +	size_t filesize;
    5.89 +	FILE *fp;
    5.90 +	char *src;
    5.91 +
    5.92 +	if(!(fp = fopen(fname, "r"))) {
    5.93 +		fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno));
    5.94 +		return 0;
    5.95 +	}
    5.96 +
    5.97 +#if defined(unix) || defined(__unix__)
    5.98 +	fstat(fileno(fp), &st);
    5.99 +	filesize = st.st_size;
   5.100 +#else
   5.101 +	fseek(fp, 0, SEEK_END);
   5.102 +	filesize = ftell(fp);
   5.103 +	fseek(fp, 0, SEEK_SET);
   5.104 +#endif	/* unix */
   5.105 +
   5.106 +	if(!(src = malloc(filesize + 1))) {
   5.107 +		fclose(fp);
   5.108 +		return 0;
   5.109 +	}
   5.110 +	fread(src, 1, filesize, fp);
   5.111 +	src[filesize] = 0;
   5.112 +	fclose(fp);
   5.113 +
   5.114 +	fprintf(stderr, "compiling %s shader: %s... ", (sdr_type == GL_VERTEX_SHADER ? "vertex" : "pixel"), fname);
   5.115 +	sdr = create_shader(src, sdr_type);
   5.116 +
   5.117 +	free(src);
   5.118 +	return sdr;
   5.119 +}
   5.120 +
   5.121 +
   5.122 +unsigned int get_vertex_shader(const char *fname)
   5.123 +{
   5.124 +	return get_shader(fname, GL_VERTEX_SHADER);
   5.125 +}
   5.126 +
   5.127 +unsigned int get_pixel_shader(const char *fname)
   5.128 +{
   5.129 +	return get_shader(fname, GL_FRAGMENT_SHADER);
   5.130 +}
   5.131 +
   5.132 +unsigned int get_shader(const char *fname, unsigned int sdr_type)
   5.133 +{
   5.134 +	unsigned int sdr;
   5.135 +#if 0
   5.136 +	if((res = get_resource(sdrman, fname))) {
   5.137 +		/* TODO: validate that the shader matches sdr_type? */
   5.138 +		return (uintptr_t)res;
   5.139 +	}
   5.140 +#endif
   5.141 +
   5.142 +	if(!(sdr = load_shader(fname, sdr_type))) {
   5.143 +		return 0;
   5.144 +	}
   5.145 +	add_shader(fname, sdr);
   5.146 +	return sdr;
   5.147 +}
   5.148 +
   5.149 +int add_shader(const char *fname, unsigned int sdr)
   5.150 +{
   5.151 +	return 0;/*add_resource(sdrman, fname, (void*)(uintptr_t)sdr);*/
   5.152 +}
   5.153 +
   5.154 +int remove_shader(const char *fname)
   5.155 +{
   5.156 +	return 0;/*remove_resource(sdrman, fname);*/
   5.157 +}
   5.158 +
   5.159 +
   5.160 +/* ---- gpu programs ---- */
   5.161 +
   5.162 +unsigned int create_program(void)
   5.163 +{
   5.164 +	unsigned int prog = glCreateProgram();
   5.165 +	assert(glGetError() == GL_NO_ERROR);
   5.166 +	return prog;
   5.167 +}
   5.168 +
   5.169 +unsigned int create_program_link(unsigned int vs, unsigned int ps)
   5.170 +{
   5.171 +	unsigned int prog;
   5.172 +
   5.173 +	if(!(prog = create_program())) {
   5.174 +		return 0;
   5.175 +	}
   5.176 +	
   5.177 +	attach_shader(prog, vs);
   5.178 +	assert(glGetError() == GL_NO_ERROR);
   5.179 +	attach_shader(prog, ps);
   5.180 +	assert(glGetError() == GL_NO_ERROR);
   5.181 +	
   5.182 +	if(link_program(prog) == -1) {
   5.183 +		free_program(prog);
   5.184 +		return 0;
   5.185 +	}
   5.186 +	return prog;
   5.187 +}
   5.188 +
   5.189 +unsigned int create_program_load(const char *vfile, const char *pfile)
   5.190 +{
   5.191 +	unsigned int vs, ps;
   5.192 +
   5.193 +	if(!(vs = get_vertex_shader(vfile)) || !(ps = get_pixel_shader(pfile))) {
   5.194 +		return 0;
   5.195 +	}
   5.196 +	return create_program_link(vs, ps);
   5.197 +}
   5.198 +
   5.199 +void free_program(unsigned int sdr)
   5.200 +{
   5.201 +	glDeleteProgram(sdr);
   5.202 +}
   5.203 +
   5.204 +void attach_shader(unsigned int prog, unsigned int sdr)
   5.205 +{
   5.206 +	glAttachShader(prog, sdr);
   5.207 +	assert(glGetError() == GL_NO_ERROR);
   5.208 +}
   5.209 +
   5.210 +int link_program(unsigned int prog)
   5.211 +{
   5.212 +	int linked, info_len, retval = 0;
   5.213 +	char *info_str = 0;
   5.214 +
   5.215 +	glLinkProgram(prog);
   5.216 +	assert(glGetError() == GL_NO_ERROR);
   5.217 +	glGetProgramiv(prog, GL_LINK_STATUS, &linked);
   5.218 +	assert(glGetError() == GL_NO_ERROR);
   5.219 +	glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
   5.220 +	assert(glGetError() == GL_NO_ERROR);
   5.221 +
   5.222 +	if(info_len) {
   5.223 +		if((info_str = malloc(info_len + 1))) {
   5.224 +			glGetProgramInfoLog(prog, info_len, 0, info_str);
   5.225 +			assert(glGetError() == GL_NO_ERROR);
   5.226 +		}
   5.227 +	}
   5.228 +
   5.229 +	if(linked) {
   5.230 +		fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str);
   5.231 +	} else {
   5.232 +		fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str);
   5.233 +		retval = -1;
   5.234 +	}
   5.235 +
   5.236 +	free(info_str);
   5.237 +	return retval;
   5.238 +}
   5.239 +
   5.240 +int bind_program(unsigned int prog)
   5.241 +{
   5.242 +	GLenum err;
   5.243 +
   5.244 +	glUseProgram(prog);
   5.245 +	if(prog && (err = glGetError()) != GL_NO_ERROR) {
   5.246 +		/* maybe the program is not linked, try to link first */
   5.247 +		if(err == GL_INVALID_OPERATION) {
   5.248 +			if(link_program(prog) == -1) {
   5.249 +				return -1;
   5.250 +			}
   5.251 +			glUseProgram(prog);
   5.252 +			return glGetError() == GL_NO_ERROR ? 0 : -1;
   5.253 +		}
   5.254 +		return -1;
   5.255 +	}
   5.256 +	return 0;
   5.257 +}
   5.258 +
   5.259 +/* ugly but I'm not going to write the same bloody code over and over */
   5.260 +#define BEGIN_UNIFORM_CODE \
   5.261 +	int loc, curr_prog; \
   5.262 +	glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \
   5.263 +	if(curr_prog != prog && bind_program(prog) == -1) { \
   5.264 +		return -1; \
   5.265 +	} \
   5.266 +	if((loc = glGetUniformLocation(prog, name)) != -1)
   5.267 +
   5.268 +#define END_UNIFORM_CODE \
   5.269 +	if(curr_prog != prog) { \
   5.270 +		bind_program(curr_prog); \
   5.271 +	} \
   5.272 +	return loc == -1 ? -1 : 0
   5.273 +
   5.274 +int set_uniform_int(unsigned int prog, const char *name, int val)
   5.275 +{
   5.276 +	BEGIN_UNIFORM_CODE {
   5.277 +		glUniform1i(loc, val);
   5.278 +	}
   5.279 +	END_UNIFORM_CODE;
   5.280 +}
   5.281 +
   5.282 +int set_uniform_float(unsigned int prog, const char *name, float val)
   5.283 +{
   5.284 +	BEGIN_UNIFORM_CODE {
   5.285 +		glUniform1f(loc, val);
   5.286 +	}
   5.287 +	END_UNIFORM_CODE;
   5.288 +}
   5.289 +
   5.290 +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z)
   5.291 +{
   5.292 +	BEGIN_UNIFORM_CODE {
   5.293 +		glUniform3f(loc, x, y, z);
   5.294 +	}
   5.295 +	END_UNIFORM_CODE;
   5.296 +}
   5.297 +
   5.298 +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w)
   5.299 +{
   5.300 +	BEGIN_UNIFORM_CODE {
   5.301 +		glUniform4f(loc, x, y, z, w);
   5.302 +	}
   5.303 +	END_UNIFORM_CODE;
   5.304 +}
   5.305 +
   5.306 +
   5.307 +int get_attrib_loc(unsigned int prog, const char *name)
   5.308 +{
   5.309 +	int loc, curr_prog;
   5.310 +	
   5.311 +	glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog);
   5.312 +	if(curr_prog != prog && bind_program(prog) == -1) {
   5.313 +		return -1;
   5.314 +	}
   5.315 +	
   5.316 +	loc = glGetAttribLocation(prog, (char*)name);
   5.317 +	
   5.318 +	if(curr_prog != prog) {
   5.319 +		bind_program(curr_prog);
   5.320 +	}
   5.321 +	return loc;
   5.322 +}
   5.323 +
   5.324 +void set_attrib_float3(int attr_loc, float x, float y, float z)
   5.325 +{
   5.326 +	glVertexAttrib3f(attr_loc, x, y, z);
   5.327 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/sdr.h	Thu Oct 21 23:39:26 2010 +0300
     6.3 @@ -0,0 +1,47 @@
     6.4 +#ifndef _SDR_H_
     6.5 +#define _SDR_H_
     6.6 +
     6.7 +#ifdef __cplusplus
     6.8 +extern "C" {
     6.9 +#endif	/* __cplusplus */
    6.10 +
    6.11 +/* ---- shaders ---- */
    6.12 +unsigned int create_vertex_shader(const char *src);
    6.13 +unsigned int create_pixel_shader(const char *src);
    6.14 +unsigned int create_shader(const char *src, unsigned int sdr_type);
    6.15 +void free_shader(unsigned int sdr);
    6.16 +
    6.17 +unsigned int load_vertex_shader(const char *fname);
    6.18 +unsigned int load_pixel_shader(const char *fname);
    6.19 +unsigned int load_shader(const char *src, unsigned int sdr_type);
    6.20 +
    6.21 +unsigned int get_vertex_shader(const char *fname);
    6.22 +unsigned int get_pixel_shader(const char *fname);
    6.23 +unsigned int get_shader(const char *fname, unsigned int sdr_type);
    6.24 +
    6.25 +int add_shader(const char *fname, unsigned int sdr);
    6.26 +int remove_shader(const char *fname);
    6.27 +
    6.28 +/* ---- gpu programs ---- */
    6.29 +unsigned int create_program(void);
    6.30 +unsigned int create_program_link(unsigned int vs, unsigned int ps);
    6.31 +unsigned int create_program_load(const char *vfile, const char *pfile);
    6.32 +void free_program(unsigned int sdr);
    6.33 +
    6.34 +void attach_shader(unsigned int prog, unsigned int sdr);
    6.35 +int link_program(unsigned int prog);
    6.36 +int bind_program(unsigned int prog);
    6.37 +
    6.38 +int set_uniform_int(unsigned int prog, const char *name, int val);
    6.39 +int set_uniform_float(unsigned int prog, const char *name, float val);
    6.40 +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z);
    6.41 +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w);
    6.42 +
    6.43 +int get_attrib_loc(unsigned int prog, const char *name);
    6.44 +void set_attrib_float3(int attr_loc, float x, float y, float z);
    6.45 +
    6.46 +#ifdef __cplusplus
    6.47 +}
    6.48 +#endif	/* __cplusplus */
    6.49 +
    6.50 +#endif	/* _SDR_H_ */