
fsraytrace and vsraytrace were crashing on Mac OS X 10.6.3 in the Apple GLSL compiler function TPPStreamCompiler::assignOperands. Removing some const qualifers made the crashes go away.
402 lines
18 KiB
C
402 lines
18 KiB
C
/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; coding: utf-8-unix -*- */
|
|
/*
|
|
Copyright (c) 2010 Kristóf Ralovich
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <GL/glew.h>
|
|
#include <GL/glut.h>
|
|
#include "shaderutil.h"
|
|
#include <math.h>
|
|
|
|
static int Win;
|
|
static int WinWidth = 256, WinHeight = 256;
|
|
static GLboolean mouseGrabbed = GL_FALSE;
|
|
static GLuint vertShader;
|
|
static GLuint program;
|
|
float rot[9] = {1,0,0, 0,1,0, 0,0,1};
|
|
|
|
static const char* vsSource =
|
|
"const float INF = 9999.9; \n"
|
|
"const float EPSILON = 0.00001; \n"
|
|
"const vec3 lightPos = vec3(0.0, 8.0, 1.0); \n"
|
|
"const vec4 backgroundColor = vec4(0.2,0.3,0.4,1); \n"
|
|
" \n"
|
|
"uniform mat3 rot; \n"
|
|
" \n"
|
|
"struct Ray \n"
|
|
"{ \n"
|
|
"vec3 orig; \n"
|
|
"vec3 dir; \n"
|
|
"}; \n"
|
|
" \n"
|
|
"struct Sphere \n"
|
|
"{ \n"
|
|
" vec3 c; \n"
|
|
" float r; \n"
|
|
"}; \n"
|
|
" \n"
|
|
"struct Isec \n"
|
|
"{ \n"
|
|
" float t; \n"
|
|
" int idx; \n"
|
|
" vec3 hit; \n"
|
|
" vec3 n; \n"
|
|
"}; \n"
|
|
" \n"
|
|
#ifdef __APPLE__
|
|
"Sphere spheres0 = Sphere( vec3(0.0,0.0,-1.0), 0.5 ); \n"
|
|
"Sphere spheres1 = Sphere( vec3(-3.0,0.0,-1.0), 1.5 ); \n"
|
|
"Sphere spheres2 = Sphere( vec3(0.0,3.0,-1.0), 0.5 ); \n"
|
|
"Sphere spheres3 = Sphere( vec3(2.0,0.0,-1.0), 1.0 ); \n"
|
|
#else
|
|
"const Sphere spheres0 = Sphere( vec3(0.0,0.0,-1.0), 0.5 ); \n"
|
|
"const Sphere spheres1 = Sphere( vec3(-3.0,0.0,-1.0), 1.5 ); \n"
|
|
"const Sphere spheres2 = Sphere( vec3(0.0,3.0,-1.0), 0.5 ); \n"
|
|
"const Sphere spheres3 = Sphere( vec3(2.0,0.0,-1.0), 1.0 ); \n"
|
|
#endif
|
|
" \n"
|
|
"// Mesa intel gen4 generates \"unsupported IR in fragment shader 13\" for\n"
|
|
"// sqrt, let's work around. \n"
|
|
"float \n"
|
|
"sqrt_hack(float f2) \n"
|
|
"{ \n"
|
|
" vec3 v = vec3(f2,0.0,0.0); \n"
|
|
" return length(v); \n"
|
|
"} \n"
|
|
" \n"
|
|
"void \n"
|
|
"intersect(const in Ray ray, \n"
|
|
" const in Sphere sph, \n"
|
|
" const in int idx, \n"
|
|
" inout Isec isec) \n"
|
|
"{ \n"
|
|
" // Project both o and the sphere to the plane perpendicular to d \n"
|
|
" // and containing c. Let x be the point where the ray intersects \n"
|
|
" // the plane. If |x-c| < r, the ray intersects the sphere. \n"
|
|
" vec3 o = ray.orig; \n"
|
|
" vec3 d = ray.dir; \n"
|
|
" vec3 n = -d; \n"
|
|
" vec3 c = sph.c; \n"
|
|
" float r = sph.r; \n"
|
|
" float t = dot(c-o,n)/dot(n,d); \n"
|
|
" vec3 x = o+d*t; \n"
|
|
" float e = length(x-c); \n"
|
|
" if(e > r) \n"
|
|
" { \n"
|
|
" // no intersection \n"
|
|
" return; \n"
|
|
" } \n"
|
|
" \n"
|
|
" // Apply Pythagorean theorem on the (intersection,x,c) triangle \n"
|
|
" // to get the distance between c and the intersection. \n"
|
|
"#define BUGGY_INTEL_GEN4_GLSL 1 \n"
|
|
"#ifndef BUGGY_INTEL_GEN4_GLSL \n"
|
|
" float f = sqrt(r*r - e*e); \n"
|
|
"#else \n"
|
|
" float f = sqrt_hack(r*r - e*e); \n"
|
|
"#endif \n"
|
|
" float dist = t - f; \n"
|
|
" if(dist < 0.0) \n"
|
|
" { \n"
|
|
" // inside the sphere \n"
|
|
" return; \n"
|
|
" } \n"
|
|
" \n"
|
|
" if(dist < EPSILON) \n"
|
|
" return; \n"
|
|
" \n"
|
|
" if(dist > isec.t) \n"
|
|
" return; \n"
|
|
" \n"
|
|
" isec.t = dist; \n"
|
|
" isec.idx = idx; \n"
|
|
" \n"
|
|
" isec.hit = ray.orig + ray.dir * isec.t; \n"
|
|
" isec.n = (isec.hit - c) / r; \n"
|
|
"} \n"
|
|
" \n"
|
|
"Isec \n"
|
|
"intersect(const in Ray ray, \n"
|
|
" const in float max_t /*= INF*/) \n"
|
|
"{ \n"
|
|
" Isec nearest; \n"
|
|
" nearest.t = max_t; \n"
|
|
" nearest.idx = -1; \n"
|
|
" \n"
|
|
" intersect(ray, spheres0, 0, nearest); \n"
|
|
" intersect(ray, spheres1, 1, nearest); \n"
|
|
" intersect(ray, spheres2, 2, nearest); \n"
|
|
" intersect(ray, spheres3, 3, nearest); \n"
|
|
" \n"
|
|
" return nearest; \n"
|
|
"} \n"
|
|
" \n"
|
|
"vec4 \n"
|
|
"idx2color(const in int idx) \n"
|
|
"{ \n"
|
|
" vec4 diff; \n"
|
|
" if(idx == 0) \n"
|
|
" diff = vec4(1.0, 0.0, 0.0, 0.0); \n"
|
|
" else if(idx == 1) \n"
|
|
" diff = vec4(0.0, 1.0, 0.0, 0.0); \n"
|
|
" else if(idx == 2) \n"
|
|
" diff = vec4(0.0, 0.0, 1.0, 0.0); \n"
|
|
" else if(idx == 3) \n"
|
|
" diff = vec4(1.0, 1.0, 0.0, 0.0); \n"
|
|
" return diff; \n"
|
|
"} \n"
|
|
" \n"
|
|
"vec4 \n"
|
|
"trace0(const in Ray ray) \n"
|
|
"{ \n"
|
|
" Isec isec = intersect(ray, INF); \n"
|
|
" \n"
|
|
" if(isec.idx == -1) \n"
|
|
" { \n"
|
|
" return backgroundColor; \n"
|
|
" } \n"
|
|
" \n"
|
|
" vec4 diff = idx2color(isec.idx); \n"
|
|
" \n"
|
|
" vec3 N = isec.n; \n"
|
|
" vec3 L = normalize(lightPos-isec.hit); \n"
|
|
" vec3 camera_dir = normalize(ray.orig - isec.hit); \n"
|
|
" return dot(N,L)*diff + pow( \n"
|
|
" clamp(dot(reflect(-L,N),camera_dir),0.0,1.0),16.0); \n"
|
|
"} \n"
|
|
" \n"
|
|
"vec4 \n"
|
|
"trace1(const in Ray ray) \n"
|
|
"{ \n"
|
|
" Isec isec = intersect(ray, INF); \n"
|
|
" \n"
|
|
" if(isec.idx == -1) \n"
|
|
" { \n"
|
|
" return backgroundColor; \n"
|
|
" } \n"
|
|
" \n"
|
|
" Ray reflRay = Ray(isec.hit, reflect(ray.dir, isec.n)); \n"
|
|
" \n"
|
|
" vec4 reflCol = trace0(reflRay); \n"
|
|
" \n"
|
|
" vec4 diff = idx2color(isec.idx) + reflCol; \n"
|
|
" \n"
|
|
" vec3 N = isec.n; \n"
|
|
" vec3 L = normalize(lightPos-isec.hit); \n"
|
|
" vec3 camera_dir = normalize(ray.orig - isec.hit); \n"
|
|
" return dot(N,L)*diff + pow( \n"
|
|
" clamp(dot(reflect(-L,N),camera_dir),0.0,1.0),16.0); \n"
|
|
"} \n"
|
|
" \n"
|
|
"void main() \n"
|
|
"{ \n"
|
|
" const vec3 cameraPos = vec3(0,0,3); \n"
|
|
" vec3 rayDir = normalize(vec3(gl_Vertex.x, gl_Vertex.y, -1.0) * rot);\n"
|
|
" Ray ray = Ray(cameraPos, rayDir); \n"
|
|
" gl_Position = gl_Vertex; \n"
|
|
" gl_FrontColor = trace1(ray); \n"
|
|
"}\n";
|
|
|
|
|
|
static
|
|
float
|
|
deg2rad(const float degree)
|
|
{
|
|
return( degree * 0.017453292519943295769236907684886F);
|
|
}
|
|
|
|
static void
|
|
rotate_xy(float* mat3, const float degreesAroundX, const float degreesAroundY)
|
|
{
|
|
const float rad1 = deg2rad(degreesAroundX);
|
|
const float c1 = cosf(rad1);
|
|
const float s1 = sinf(rad1);
|
|
const float rad2 = deg2rad(degreesAroundY);
|
|
const float c2 = cosf(rad2);
|
|
const float s2 = sinf(rad2);
|
|
mat3[0] = c2; mat3[3] = 0.0F; mat3[6] = s2;
|
|
mat3[1] = s1*s2; mat3[4] = c1; mat3[7] = -s1*c2;
|
|
mat3[2] = -c1*s2;mat3[5] = s1; mat3[8] = c1*c2;
|
|
}
|
|
|
|
static void
|
|
identity(float* mat3)
|
|
{
|
|
mat3[0] = 1.0F; mat3[3] = 0.0F; mat3[6] = 0.0F;
|
|
mat3[1] = 0.0F; mat3[4] = 1.0F; mat3[7] = 0.0F;
|
|
mat3[2] = 0.0F; mat3[5] = 0.0F; mat3[8] = 1.0F;
|
|
}
|
|
|
|
static void
|
|
Draw(void)
|
|
{
|
|
const float w = 0.5F * WinWidth;
|
|
const float h = 0.5F * WinHeight;
|
|
int x,y;
|
|
|
|
GLint location = glGetUniformLocation(program, "rot");
|
|
|
|
glUseProgram(program);
|
|
glUniformMatrix3fv(location, 1, 0, rot);
|
|
glBegin(GL_POINTS);
|
|
for(y = 0; y < WinHeight; y++)
|
|
{
|
|
for(x = 0; x < WinWidth; x++)
|
|
{
|
|
const float posx = x / w - 1.0F;
|
|
const float posy = y / h - 1.0F;
|
|
glVertex2f(posx, posy);
|
|
}
|
|
}
|
|
glEnd();
|
|
glUseProgram(0);
|
|
|
|
glutSwapBuffers();
|
|
|
|
{
|
|
static int frames = 0;
|
|
static int t0 = 0;
|
|
static int t1 = 0;
|
|
float dt;
|
|
frames++;
|
|
t1 = glutGet(GLUT_ELAPSED_TIME);
|
|
dt = (float)(t1-t0)/1000.0F;
|
|
if (dt >= 5.0F)
|
|
{
|
|
float fps = (float)frames / dt;
|
|
printf("%f FPS (%d frames in %f seconds)\n", fps, frames, dt);
|
|
frames = 0;
|
|
t0 = t1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
Reshape(int width, int height)
|
|
{
|
|
WinWidth = width;
|
|
WinHeight = height;
|
|
glViewport(0, 0, width, height);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
}
|
|
|
|
|
|
static void
|
|
Key(unsigned char key, int x, int y)
|
|
{
|
|
if(key == 27)
|
|
{
|
|
glutDestroyWindow(Win);
|
|
exit(0);
|
|
}
|
|
glutPostRedisplay();
|
|
}
|
|
|
|
|
|
static
|
|
void
|
|
drag(int x, int y)
|
|
{
|
|
float scale = 1.5F;
|
|
if(mouseGrabbed)
|
|
{
|
|
static GLfloat xRot = 0, yRot = 0;
|
|
xRot = (float)(x - WinWidth/2) / scale;
|
|
yRot = (float)(y - WinHeight/2) / scale;
|
|
identity(rot);
|
|
rotate_xy(rot, yRot, xRot);
|
|
glutPostRedisplay();
|
|
}
|
|
}
|
|
|
|
|
|
static
|
|
void
|
|
mouse(int button, int state, int x, int y)
|
|
{
|
|
mouseGrabbed = (state == GLUT_DOWN);
|
|
}
|
|
|
|
|
|
static void
|
|
Init(void)
|
|
{
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
if(!ShadersSupported())
|
|
{
|
|
fprintf(stderr, "Shaders are not supported!\n");
|
|
exit(-1);
|
|
}
|
|
|
|
vertShader = CompileShaderText(GL_VERTEX_SHADER, vsSource);
|
|
program = LinkShaders(vertShader, 0);
|
|
glUseProgram(0);
|
|
|
|
if(glGetError() != 0)
|
|
{
|
|
fprintf(stderr, "Shaders were not loaded!\n");
|
|
exit(-1);
|
|
}
|
|
|
|
if(!glIsShader(vertShader))
|
|
{
|
|
fprintf(stderr, "Vertex shader failed!\n");
|
|
exit(-1);
|
|
}
|
|
|
|
if(!glIsProgram(program))
|
|
{
|
|
fprintf(stderr, "Shader program failed!\n");
|
|
exit(-1);
|
|
}
|
|
|
|
printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
|
|
}
|
|
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
glutInitWindowSize(WinWidth, WinHeight);
|
|
glutInit(&argc, argv);
|
|
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
|
|
Win = glutCreateWindow(argv[0]);
|
|
glewInit();
|
|
glutReshapeFunc(Reshape);
|
|
glutKeyboardFunc(Key);
|
|
glutDisplayFunc(Draw);
|
|
glutIdleFunc(Draw);
|
|
glutMouseFunc(mouse);
|
|
glutMotionFunc(drag);
|
|
Init();
|
|
glutMainLoop();
|
|
return 0;
|
|
}
|
|
|