Skip to content

Instantly share code, notes, and snippets.

@jtsiomb
Created August 18, 2018 16:35
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jtsiomb/b63ab251a76f60306913a15486f65a7a to your computer and use it in GitHub Desktop.
Save jtsiomb/b63ab251a76f60306913a15486f65a7a to your computer and use it in GitHub Desktop.
OpenGL user clip planes example fixed function & shaders (discard)
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <assert.h>
#include <alloca.h>
#include <GL/glew.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
/* XXX SHADERS
* Fake pixel-shader clipping by discarding fragments which end up in the
* negative half-space of any of the clipping planes. Here I'm doing clipping
* in local space, which is why I'm passing local_vertex to the pixel shader.
*/
const char *vshader =
"varying vec4 local_vertex;\n"
"\n"
"void main()\n"
"{\n"
" local_vertex = gl_Vertex;\n"
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
" vec3 vpos = (gl_ModelViewMatrix * gl_Vertex).xyz;\n"
" vec3 norm = gl_NormalMatrix * gl_Normal;\n"
" norm = faceforward(norm, vpos, norm);\n"
" vec3 ldir = normalize(gl_LightSource[0].position.xyz - vpos);\n"
"\n"
" float ndotl = max(dot(norm, ldir), 0.0);\n"
"\n"
" gl_FrontColor.rgb = gl_FrontMaterial.diffuse.rgb * ndotl;\n"
" gl_FrontColor.a = gl_FrontMaterial.diffuse.a;\n"
" gl_BackColor.rgb = gl_BackMaterial.diffuse.rgb * ndotl;\n"
" gl_BackColor.a = gl_BackMaterial.diffuse.a;\n"
"}\n";
const char *pshader =
"uniform vec4 clip_plane[4];\n"
"uniform int num_clip_planes;\n"
"\n"
"varying vec4 local_vertex;\n"
"\n"
"void main()\n"
"{\n"
" for(int i=0; i<num_clip_planes; i++) {\n"
" // calculate signed plane-vertex distance\n"
" float d = dot(clip_plane[i], local_vertex);\n"
" if(d < 0.0) discard;\n"
" }\n"
" gl_FragColor = gl_Color;\n"
"}\n";
int init(void);
void cleanup(void);
void idle(void);
void display(void);
void draw_teapot(void);
void material(unsigned int side, float r, float g, float b);
void reshape(int x, int y);
void keydown(unsigned char key, int x, int y);
void mouse(int bn, int st, int x, int y);
void motion(int x, int y);
void glprintf(const char *fmt, ...);
unsigned int create_shader(int type, const char *src);
unsigned int create_program(const char *vsrc, const char *psrc);
int win_width, win_height;
float cam_theta, cam_phi = 25, cam_dist = 8;
double tsec;
unsigned int sdrprog;
int uloc_numplanes, uloc_cplane[4];
int use_sdr;
struct plane {
float nx, ny, nz, d;
} clip_planes[] = {
{0, 0, -1, 0.3},
{0, 0, 1, 0.3},
};
int num_clip_planes = sizeof clip_planes / sizeof *clip_planes;
float light_pos[] = {-5, 10, 8, 1};
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitWindowSize(800, 600);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
glutCreateWindow("clip planes example");
glutDisplayFunc(display);
glutIdleFunc(idle);
glutReshapeFunc(reshape);
glutKeyboardFunc(keydown);
glutMouseFunc(mouse);
glutMotionFunc(motion);
if(init() == -1) {
return 1;
}
atexit(cleanup);
glutMainLoop();
return 0;
}
int init(void)
{
int i;
glewInit();
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
glEnable(GL_VERTEX_PROGRAM_TWO_SIDE);
if(!(sdrprog = create_program(vshader, pshader))) {
return -1;
}
glUseProgram(sdrprog);
uloc_numplanes = glGetUniformLocation(sdrprog, "num_clip_planes");
for(i=0; i<4; i++) {
char name[32];
sprintf(name, "clip_plane[%d]", i);
uloc_cplane[i] = glGetUniformLocation(sdrprog, name);
}
glUseProgram(0);
return 0;
}
void cleanup(void)
{
}
void idle(void)
{
glutPostRedisplay();
}
void display(void)
{
tsec = (double)glutGet(GLUT_ELAPSED_TIME) / 1000.0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -cam_dist);
glRotatef(cam_phi, 1, 0, 0);
glRotatef(cam_theta, 0, 1, 0);
glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
draw_teapot();
/* floor */
glPushMatrix();
glTranslatef(0, -0.8, 0);
material(GL_FRONT_AND_BACK, 0.5, 0.5, 0.5);
glBegin(GL_QUADS);
glNormal3f(0, 1, 0);
glVertex3f(-5, 0, 5);
glVertex3f(5, 0, 5);
glVertex3f(5, 0, -5);
glVertex3f(-5, 0, -5);
glEnd();
glPopMatrix();
glprintf("mode: %s", use_sdr ? "shaders" : "fixed function");
glutSwapBuffers();
assert(glGetError() == GL_NO_ERROR);
}
void draw_teapot(void)
{
int i;
if(use_sdr) {
glUseProgram(sdrprog);
}
material(GL_FRONT, 0.2, 0.4, 1.0);
material(GL_BACK, 1.0, 0.4, 0.2);
glPushMatrix();
glTranslatef(sin(tsec) * 2.0, 0, 0);
glRotatef(tsec * 100.0, 0, 1, 0);
for(i=0; i<num_clip_planes; i++) {
double peqn[4];
peqn[0] = clip_planes[i].nx;
peqn[1] = clip_planes[i].ny;
peqn[2] = clip_planes[i].nz;
peqn[3] = clip_planes[i].d;
if(use_sdr) {
/* XXX SHADERS
* clipping planes are passed to the shaders as regular uniforms
*/
if(uloc_cplane[i] != -1) {
glUniform4f(uloc_cplane[i], peqn[0], peqn[1], peqn[2], peqn[3]);
}
} else {
/* XXX FIXED FUNCTION
* set clipping planes using glClipPlane, and use glEnable to
* enable them one by one.
*
* The plane equation (nx, ny, nz, dist) gets transformed by the
* inverse of the current modelview matrix, to take it to the
* object's local space, which is where clipping will be performed.
*
* If the modelview matrix was identity at this point, it would be
* as if we were defining clip planes in view space.
*/
glClipPlane(GL_CLIP_PLANE0 + i, peqn);
glEnable(GL_CLIP_PLANE0 + i);
}
}
if(use_sdr && uloc_numplanes != -1) {
glUniform1i(uloc_numplanes, num_clip_planes);
}
glFrontFace(GL_CW);
glutSolidTeapot(1.0);
glFrontFace(GL_CCW);
for(i=0; i<num_clip_planes; i++) {
if(!use_sdr) {
glDisable(GL_CLIP_PLANE0 + i);
}
}
if(use_sdr) {
glUseProgram(0);
}
glPopMatrix();
}
void material(unsigned int side, float r, float g, float b)
{
float color[4];
color[0] = r;
color[1] = g;
color[2] = b;
color[3] = 1.0f;
glMaterialfv(side, GL_AMBIENT_AND_DIFFUSE, color);
}
void reshape(int x, int y)
{
win_width = x;
win_height = y;
glViewport(0, 0, x, y);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (float)x / (float)y, 0.5, 500.0);
}
void keydown(unsigned char key, int x, int y)
{
switch(key) {
case 27:
exit(0);
case 's':
use_sdr = !use_sdr;
glutPostRedisplay();
break;
}
}
int prev_x, prev_y;
int bnstate[8];
void mouse(int bn, int st, int x, int y)
{
bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN ? 1 : 0;
prev_x = x;
prev_y = y;
}
void motion(int x, int y)
{
int dx = x - prev_x;
int dy = y - prev_y;
prev_x = x;
prev_y = y;
if(!dx && !dy) return;
if(bnstate[0]) {
cam_theta += dx * 0.5;
cam_phi += dy * 0.5;
if(cam_phi < -90) cam_phi = -90;
if(cam_phi > 90) cam_phi = 90;
glutPostRedisplay();
}
if(bnstate[2]) {
cam_dist += dy * 0.1;
if(cam_dist < 0.0) cam_dist = 0.0;
glutPostRedisplay();
}
}
void glprintf(const char *fmt, ...)
{
va_list ap;
char buf[512], *ptr;
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_LIGHTING);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, win_width, 0, win_height, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRasterPos2i(10, 10);
glColor3f(1, 1, 0);
ptr = buf;
while(*ptr) {
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *ptr++);
}
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopAttrib();
}
unsigned int create_shader(int type, const char *src)
{
unsigned int sdr;
int st, loglen;
printf("compiling %s shader ... ", type == GL_VERTEX_SHADER ? "vertex" : "pixel");
fflush(stdout);
sdr = glCreateShader(type);
glShaderSource(sdr, 1, &src, 0);
glCompileShader(sdr);
glGetShaderiv(sdr, GL_COMPILE_STATUS, &st);
puts(st ? "done." : "failed!");
glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &loglen);
if(loglen > 0) {
char *log = alloca(loglen + 1);
glGetShaderInfoLog(sdr, loglen, 0, log);
printf("compiler output:\n%s\n", log);
}
if(!st) {
glDeleteShader(sdr);
return 0;
}
return sdr;
}
unsigned int create_program(const char *vsrc, const char *psrc)
{
unsigned int prog, vs, ps;
int st, loglen;
if(!(vs = create_shader(GL_VERTEX_SHADER, vsrc))) {
return 0;
}
if(!(ps = create_shader(GL_FRAGMENT_SHADER, psrc))) {
glDeleteShader(vs);
return 0;
}
fputs("linking shader program ... ", stdout);
fflush(stdout);
prog = glCreateProgram();
glAttachShader(prog, vs);
glAttachShader(prog, ps);
glLinkProgram(prog);
glGetProgramiv(prog, GL_LINK_STATUS, &st);
puts(st ? "done." : "failed!");
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &loglen);
if(loglen > 0) {
char *log = alloca(loglen + 1);
glGetProgramInfoLog(prog, loglen, 0, log);
printf("linker output:\n%s\n", log);
}
if(!st) {
glDeleteProgram(prog);
glDeleteShader(vs);
glDeleteShader(ps);
return 0;
}
return prog;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment