blob: 89df64fc718deaf0dce2aa6a2b0fc248309d0adc [file] [log] [blame]
/**
* Demonstration of doing triangle rasterization with a fragment program.
* Basic idea:
* 1. Draw screen-aligned quad / bounding box around the triangle verts.
* 2. For each pixel in the quad, determine if pixel is inside/outside
* the triangle edges.
*
* Brian Paul
* 1 Aug 2007
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glext.h>
#include "extfuncs.h"
#include "shaderutil.h"
static GLint WinWidth = 300, WinHeight = 300;
static char *FragProgFile = NULL;
static char *VertProgFile = NULL;
static GLuint fragShader;
static GLuint vertShader;
static GLuint program;
static GLint win = 0;
static GLboolean anim = GL_TRUE;
static GLfloat Zrot = 0.0f;
static GLint uv0, uv1, uv2;
static const GLfloat TriVerts[3][2] = {
{ 50, 50 },
{ 250, 50 },
{ 150, 250 }
};
static void
RotateVerts(GLfloat a,
GLuint n, const GLfloat vertsIn[][2], GLfloat vertsOut[][2])
{
GLuint i;
GLfloat cx = WinWidth / 2, cy = WinHeight / 2;
for (i = 0; i < n; i++) {
float x = vertsIn[i][0] - cx;
float y = vertsIn[i][1] - cy;
vertsOut[i][0] = x * cos(a) + y * sin(a) + cx;
vertsOut[i][1] = -x * sin(a) + y * cos(a) + cy;
}
}
static void
ComputeBounds(GLuint n, GLfloat vertsIn[][2],
GLfloat *xmin, GLfloat *ymin,
GLfloat *xmax, GLfloat *ymax)
{
GLuint i;
*xmin = *xmax = vertsIn[0][0];
*ymin = *ymax = vertsIn[0][1];
for (i = 1; i < n; i++) {
if (vertsIn[i][0] < *xmin)
*xmin = vertsIn[i][0];
else if (vertsIn[i][0] > *xmax)
*xmax = vertsIn[i][0];
if (vertsIn[i][1] < *ymin)
*ymin = vertsIn[i][1];
else if (vertsIn[i][1] > *ymax)
*ymax = vertsIn[i][1];
}
}
static void
Redisplay(void)
{
GLfloat v[3][2], xmin, ymin, xmax, ymax;
RotateVerts(Zrot, 3, TriVerts, v);
ComputeBounds(3, v, &xmin, &ymin, &xmax, &ymax);
glUniform2fv_func(uv0, 1, v[0]);
glUniform2fv_func(uv1, 1, v[1]);
glUniform2fv_func(uv2, 1, v[2]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glBegin(GL_POLYGON);
glVertex2f(xmin, ymin);
glVertex2f(xmax, ymin);
glVertex2f(xmax, ymax);
glVertex2f(xmin, ymax);
glEnd();
glPopMatrix();
glutSwapBuffers();
}
static void
Idle(void)
{
if (anim) {
Zrot = glutGet(GLUT_ELAPSED_TIME) * 0.0005;
glutPostRedisplay();
}
else
abort();
}
static void
Reshape(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, 0, height, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
static void
CleanUp(void)
{
glDeleteShader_func(fragShader);
glDeleteShader_func(vertShader);
glDeleteProgram_func(program);
glutDestroyWindow(win);
}
static void
Key(unsigned char key, int x, int y)
{
(void) x;
(void) y;
switch(key) {
case ' ':
case 'a':
anim = !anim;
if (anim)
glutIdleFunc(Idle);
else
glutIdleFunc(NULL);
break;
case 'z':
Zrot = 0;
break;
case 's':
Zrot += 0.05;
break;
case 27:
CleanUp();
exit(0);
break;
}
glutPostRedisplay();
}
static void
Init(void)
{
static const char *fragShaderText =
"uniform vec2 v0, v1, v2; \n"
"float crs(const vec2 u, const vec2 v) \n"
"{ \n"
" return u.x * v.y - u.y * v.x; \n"
"} \n"
"\n"
"void main() {\n"
" vec2 p = gl_FragCoord.xy; \n"
" if (crs(v1 - v0, p - v0) >= 0 && \n"
" crs(v2 - v1, p - v1) >= 0 && \n"
" crs(v0 - v2, p - v2) >= 0) \n"
" gl_FragColor = vec4(1.0); \n"
" else \n"
" gl_FragColor = vec4(0.5); \n"
"}\n";
static const char *vertShaderText =
"void main() {\n"
" gl_Position = ftransform(); \n"
"}\n";
if (!ShadersSupported())
exit(1);
GetExtensionFuncs();
vertShader = CompileShaderText(GL_VERTEX_SHADER, vertShaderText);
fragShader = CompileShaderText(GL_FRAGMENT_SHADER, fragShaderText);
program = LinkShaders(vertShader, fragShader);
glUseProgram_func(program);
uv0 = glGetUniformLocation_func(program, "v0");
uv1 = glGetUniformLocation_func(program, "v1");
uv2 = glGetUniformLocation_func(program, "v2");
printf("Uniforms: %d %d %d\n", uv0, uv1, uv2);
/*assert(glGetError() == 0);*/
glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
glEnable(GL_DEPTH_TEST);
printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
assert(glIsProgram_func(program));
assert(glIsShader_func(fragShader));
assert(glIsShader_func(vertShader));
glColor3f(1, 0, 0);
}
static void
ParseOptions(int argc, char *argv[])
{
int i;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-fs") == 0) {
FragProgFile = argv[i+1];
}
else if (strcmp(argv[i], "-vs") == 0) {
VertProgFile = argv[i+1];
}
}
}
int
main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowPosition( 0, 0);
glutInitWindowSize(WinWidth, WinHeight);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
win = glutCreateWindow(argv[0]);
glutReshapeFunc(Reshape);
glutKeyboardFunc(Key);
glutDisplayFunc(Redisplay);
if (anim)
glutIdleFunc(Idle);
ParseOptions(argc, argv);
Init();
glutMainLoop();
return 0;
}