Created
August 18, 2018 16:35
-
-
Save jtsiomb/b63ab251a76f60306913a15486f65a7a to your computer and use it in GitHub Desktop.
OpenGL user clip planes example fixed function & shaders (discard)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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