summaryrefslogtreecommitdiff
path: root/progs/glsl
diff options
context:
space:
mode:
authorJouk <joukj@tarantella.nano.tudelft.nl>2007-10-02 15:17:23 +0200
committerJouk <joukj@tarantella.nano.tudelft.nl>2007-10-02 15:17:23 +0200
commit584b84256b07e106cd7295495355eb21226465d7 (patch)
tree028d47d265d01f3f96787792fbd41d495d60856c /progs/glsl
parenteb9a5b6d5127858b01ec12672c999e7d25cd7aed (diff)
parentde1d725f442caa4d8ecbac3256b5a33d1f4a1257 (diff)
Merge branch 'master' of git+ssh://joukj@git.freedesktop.org/git/mesa/mesa
Diffstat (limited to 'progs/glsl')
-rw-r--r--progs/glsl/Makefile13
-rw-r--r--progs/glsl/bitmap.c368
-rw-r--r--progs/glsl/points.c305
-rw-r--r--progs/glsl/trirast.c326
4 files changed, 1009 insertions, 3 deletions
diff --git a/progs/glsl/Makefile b/progs/glsl/Makefile
index 37fa312c30..8b44239b43 100644
--- a/progs/glsl/Makefile
+++ b/progs/glsl/Makefile
@@ -8,13 +8,16 @@ INCDIR = $(TOP)/include
LIB_DEP = $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLU_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLUT_LIB_NAME)
PROGS = \
+ bitmap \
brick \
bump \
deriv \
mandelbrot \
noise \
+ points \
+ texdemo1 \
toyball \
- texdemo1
+ trirast
##### RULES #####
@@ -25,7 +28,7 @@ PROGS = \
# make executable from .c file:
.c: $(LIB_DEP)
- $(CC) -I$(INCDIR) $(CFLAGS) $< $(APP_LIB_DEPS) -o $@
+ $(CC) -I$(INCDIR) $(CFLAGS) $(LDFLAGS) $< $(APP_LIB_DEPS) -o $@
##### TARGETS #####
@@ -48,16 +51,20 @@ readtex.h: $(TOP)/progs/util/readtex.h
readtex.o: readtex.c readtex.h
$(CC) -c -I$(INCDIR) $(CFLAGS) readtex.c
+bitmap.c: extfuncs.h
+
brick.c: extfuncs.h
bump.c: extfuncs.h
mandelbrot.c: extfuncs.h
+points.c: extfuncs.h
+
toyball.c: extfuncs.h
texdemo1: texdemo1.o readtex.o
- $(CC) -I$(INCDIR) $(CFLAGS) texdemo1.o readtex.o $(APP_LIB_DEPS) -o $@
+ $(CC) -I$(INCDIR) $(CFLAGS) $(LDFLAGS) texdemo1.o readtex.o $(APP_LIB_DEPS) -o $@
texdemo1.o: texdemo1.c readtex.h extfuncs.h
$(CC) -c -I$(INCDIR) $(CFLAGS) texdemo1.c
diff --git a/progs/glsl/bitmap.c b/progs/glsl/bitmap.c
new file mode 100644
index 0000000000..4b62686cbf
--- /dev/null
+++ b/progs/glsl/bitmap.c
@@ -0,0 +1,368 @@
+/**
+ * Implement glRasterPos + glBitmap with textures + shaders.
+ * Brian Paul
+ * 14 May 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"
+
+
+static GLuint FragShader;
+static GLuint VertShader;
+static GLuint Program;
+
+static GLint Win = 0;
+static GLint WinWidth = 500, WinHeight = 500;
+static GLboolean Anim = GL_TRUE;
+static GLboolean Bitmap = GL_FALSE;
+static GLfloat Xrot = 20.0f, Yrot = 70.0f;
+static GLint uTex, uScale;
+static GLuint Textures[2];
+
+#define TEX_WIDTH 16
+#define TEX_HEIGHT 8
+
+
+static void
+BitmapText(const char *s)
+{
+ while (*s) {
+ glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
+ s++;
+ }
+}
+
+
+static void
+Redisplay(void)
+{
+ static const GLfloat px[3] = { 1.2, 0, 0};
+ static const GLfloat nx[3] = {-1.2, 0, 0};
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+ glRotatef(Xrot, 1.0f, 0.0f, 0.0f);
+ glRotatef(Yrot, 0.0f, 1.0f, 0.0f);
+
+ glEnable(GL_LIGHTING);
+
+ glPushMatrix();
+ glScalef(0.5, 0.5, 0.5);
+ glutSolidDodecahedron();
+ glPopMatrix();
+
+ glDisable(GL_LIGHTING);
+
+ glColor3f(0, 1, 0);
+ glBegin(GL_LINES);
+ glVertex3f(-1, 0, 0);
+ glVertex3f( 1, 0, 0);
+ glEnd();
+
+ glColor3f(1, 1, 0);
+
+ if (Bitmap) {
+ glRasterPos3fv(px);
+ BitmapText("+X");
+ glRasterPos3fv(nx);
+ BitmapText("-X");
+ }
+ else {
+ glUseProgram_func(Program);
+
+ /* vertex positions (deltas) depend on texture size and window size */
+ if (uScale != -1) {
+ glUniform2f_func(uScale,
+ 2.0 * TEX_WIDTH / WinWidth,
+ 2.0 * TEX_HEIGHT / WinHeight);
+ }
+
+ /* draw +X */
+ glBindTexture(GL_TEXTURE_2D, Textures[0]);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex3fv(px);
+ glTexCoord2f(1, 0); glVertex3fv(px);
+ glTexCoord2f(1, 1); glVertex3fv(px);
+ glTexCoord2f(0, 1); glVertex3fv(px);
+ glEnd();
+
+ /* draw -X */
+ glBindTexture(GL_TEXTURE_2D, Textures[1]);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex3fv(nx);
+ glTexCoord2f(1, 0); glVertex3fv(nx);
+ glTexCoord2f(1, 1); glVertex3fv(nx);
+ glTexCoord2f(0, 1); glVertex3fv(nx);
+ glEnd();
+
+ glUseProgram_func(0);
+ }
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void
+Idle(void)
+{
+ Yrot = glutGet(GLUT_ELAPSED_TIME) * 0.01;
+ glutPostRedisplay();
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ WinWidth = width;
+ WinHeight = height;
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0f, 0.0f, -10.0f);
+}
+
+
+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 'b':
+ Bitmap = !Bitmap;
+ if (Bitmap)
+ printf("Using glBitmap\n");
+ else
+ printf("Using billboard texture\n");
+ break;
+ case 27:
+ glDeleteShader_func(FragShader);
+ glDeleteShader_func(VertShader);
+ glDeleteProgram_func(Program);
+ glutDestroyWindow(Win);
+ exit(0);
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+SpecialKey(int key, int x, int y)
+{
+ const GLfloat step = 0.125f;
+ switch(key) {
+ case GLUT_KEY_UP:
+ Xrot -= step;
+ break;
+ case GLUT_KEY_DOWN:
+ Xrot += step;
+ break;
+ case GLUT_KEY_LEFT:
+ Yrot -= step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Yrot += step;
+ break;
+ }
+ /*printf("Xrot: %f Yrot: %f\n", Xrot, Yrot);*/
+ glutPostRedisplay();
+}
+
+
+static void
+MakeTexImage(const char *p, GLuint texobj)
+{
+ GLubyte image[TEX_HEIGHT][TEX_WIDTH];
+ GLuint i, j, k;
+
+ for (i = 0; i < TEX_HEIGHT; i++) {
+ for (j = 0; j < TEX_WIDTH; j++) {
+ k = i * TEX_WIDTH + j;
+ if (p[k] == ' ') {
+ image[i][j] = 0;
+ }
+ else {
+ image[i][j] = 255;
+ }
+ }
+ }
+
+ glBindTexture(GL_TEXTURE_2D, texobj);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY, TEX_WIDTH, TEX_HEIGHT, 0,
+ GL_RED, GL_UNSIGNED_BYTE, image);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+}
+
+
+static void
+MakeBitmapTextures(void)
+{
+ const char *px =
+ " X X "
+ " X X X "
+ " X X X "
+ " XXXXX X "
+ " X X X "
+ " X X X "
+ " X X "
+ " X X ";
+ const char *nx =
+ " X X "
+ " X X "
+ " X X "
+ " XXXXX X "
+ " X X "
+ " X X "
+ " X X "
+ " X X ";
+ glGenTextures(2, Textures);
+ MakeTexImage(px, Textures[0]);
+ MakeTexImage(nx, Textures[1]);
+}
+
+
+static void
+LoadAndCompileShader(GLuint shader, const char *text)
+{
+ GLint stat;
+
+ glShaderSource_func(shader, 1, (const GLchar **) &text, NULL);
+
+ glCompileShader_func(shader);
+
+ glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat);
+ if (!stat) {
+ GLchar log[1000];
+ GLsizei len;
+ glGetShaderInfoLog_func(shader, 1000, &len, log);
+ fprintf(stderr, "fslight: problem compiling shader:\n%s\n", log);
+ exit(1);
+ }
+}
+
+
+static void
+CheckLink(GLuint prog)
+{
+ GLint stat;
+ glGetProgramiv_func(prog, GL_LINK_STATUS, &stat);
+ if (!stat) {
+ GLchar log[1000];
+ GLsizei len;
+ glGetProgramInfoLog_func(prog, 1000, &len, log);
+ fprintf(stderr, "Linker error:\n%s\n", log);
+ }
+}
+
+
+static void
+Init(void)
+{
+ /* Fragment shader: modulate raster color by texture, discard fragments
+ * with alpha < 1.0
+ */
+ static const char *fragShaderText =
+ "uniform sampler2D tex2d; \n"
+ "void main() {\n"
+ " vec4 c = texture2D(tex2d, gl_TexCoord[0].xy); \n"
+ " if (c.w < 1.0) \n"
+ " discard; \n"
+ " gl_FragColor = c * gl_Color; \n"
+ "}\n";
+ /* Vertex shader: compute new vertex position based on incoming vertex pos,
+ * texcoords and special scale factor.
+ */
+ static const char *vertShaderText =
+ "uniform vec2 scale; \n"
+ "void main() {\n"
+ " vec4 p = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
+ " gl_Position.xy = p.xy + gl_MultiTexCoord0.xy * scale * p.w; \n"
+ " gl_Position.zw = p.zw; \n"
+ " gl_TexCoord[0] = gl_MultiTexCoord0; \n"
+ " gl_FrontColor = gl_Color; \n"
+ "}\n";
+ const char *version;
+
+ version = (const char *) glGetString(GL_VERSION);
+ if (version[0] != '2' || version[1] != '.') {
+ printf("This program requires OpenGL 2.x, found %s\n", version);
+ exit(1);
+ }
+ printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
+
+ GetExtensionFuncs();
+
+ FragShader = glCreateShader_func(GL_FRAGMENT_SHADER);
+ LoadAndCompileShader(FragShader, fragShaderText);
+
+ VertShader = glCreateShader_func(GL_VERTEX_SHADER);
+ LoadAndCompileShader(VertShader, vertShaderText);
+
+ Program = glCreateProgram_func();
+ glAttachShader_func(Program, FragShader);
+ glAttachShader_func(Program, VertShader);
+ glLinkProgram_func(Program);
+ CheckLink(Program);
+ glUseProgram_func(Program);
+
+ uScale = glGetUniformLocation_func(Program, "scale");
+ uTex = glGetUniformLocation_func(Program, "tex2d");
+ if (uTex != -1) {
+ glUniform1i_func(uTex, 0); /* tex unit 0 */
+ }
+
+ glUseProgram_func(0);
+
+ glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_NORMALIZE);
+ glEnable(GL_LIGHT0);
+
+ MakeBitmapTextures();
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowSize(WinWidth, WinHeight);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+ Win = glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutSpecialFunc(SpecialKey);
+ glutDisplayFunc(Redisplay);
+ if (Anim)
+ glutIdleFunc(Idle);
+ Init();
+ glutMainLoop();
+ return 0;
+}
+
+
diff --git a/progs/glsl/points.c b/progs/glsl/points.c
new file mode 100644
index 0000000000..85115de504
--- /dev/null
+++ b/progs/glsl/points.c
@@ -0,0 +1,305 @@
+/**
+ * Implement smooth (AA) points with shaders.
+ * A simple variation could be used for sprite points.
+ * Brian Paul
+ * 29 July 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"
+
+
+static GLuint FragShader;
+static GLuint VertShader;
+static GLuint Program;
+
+static GLint Win = 0;
+static GLint WinWidth = 500, WinHeight = 200;
+static GLfloat Xpos = 0.0f, Ypos = 0.0f;
+static GLint uViewportInv;
+static GLboolean Smooth = GL_TRUE, Blend = GL_TRUE;
+
+
+/**
+ * Issue vertices for a "shader point".
+ * The position is duplicated, only texcoords (or other vertex attrib) change.
+ * The vertex program will compute the "real" quad corners.
+ */
+static void
+PointVertex3f(GLfloat x, GLfloat y, GLfloat z)
+{
+ glTexCoord2f(-1, -1);
+ glVertex3f(x, y, z);
+
+ glTexCoord2f( 1, -1);
+ glVertex3f(x, y, z);
+
+ glTexCoord2f( 1, 1);
+ glVertex3f(x, y, z);
+
+ glTexCoord2f(-1, 1);
+ glVertex3f(x, y, z);
+}
+
+
+static void
+DrawPoints(GLboolean shaderPoints)
+{
+ int i;
+ for (i = 0; i < 9; i++) {
+ GLfloat x = i - 4, y = 0, z = 0;
+ /* note: can't call glPointSize inside Begin/End :( */
+ glPointSize( 2 + i * 5 );
+ if (shaderPoints) {
+ glBegin(GL_QUADS);
+ PointVertex3f(x, y, z);
+ glEnd();
+ }
+ else {
+ glBegin(GL_POINTS);
+ glVertex3f(x, y, z);
+ glEnd();
+ }
+ }
+}
+
+
+/**
+ * Top row of points rendered convetionally,
+ * bottom row rendered with shaders.
+ */
+static void
+Redisplay(void)
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ if (Smooth)
+ glEnable(GL_POINT_SMOOTH);
+ else
+ glDisable(GL_POINT_SMOOTH);
+
+ if (Blend)
+ glEnable(GL_BLEND);
+ else
+ glDisable(GL_BLEND);
+
+ glPushMatrix();
+ glTranslatef(Xpos, Ypos, 0);
+
+ /*
+ * regular points
+ */
+ glPushMatrix();
+ glTranslatef(0, 1.2, 0);
+ glUseProgram_func(0);
+ DrawPoints(GL_FALSE);
+ glPopMatrix();
+
+ /*
+ * shader points
+ */
+ glPushMatrix();
+ glTranslatef(0, -1.2, 0);
+ glUseProgram_func(Program);
+ if (uViewportInv != -1) {
+ glUniform2f_func(uViewportInv, 1.0 / WinWidth, 1.0 / WinHeight);
+ }
+ DrawPoints(GL_TRUE);
+ glPopMatrix();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ WinWidth = width;
+ WinHeight = height;
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -1.0, 1.0, 4.0, 30.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0f, 0.0f, -20.0f);
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+
+ switch(key) {
+ case 'b':
+ Blend = !Blend;
+ break;
+ case 's':
+ Smooth = !Smooth;
+ break;
+ case 27:
+ glDeleteShader_func(FragShader);
+ glDeleteShader_func(VertShader);
+ glDeleteProgram_func(Program);
+ glutDestroyWindow(Win);
+ exit(0);
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+SpecialKey(int key, int x, int y)
+{
+ const GLfloat step = 1/100.0;
+ switch(key) {
+ case GLUT_KEY_UP:
+ Ypos += step;
+ break;
+ case GLUT_KEY_DOWN:
+ Ypos -= step;
+ break;
+ case GLUT_KEY_LEFT:
+ Xpos -= step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Xpos += step;
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+LoadAndCompileShader(GLuint shader, const char *text)
+{
+ GLint stat;
+
+ glShaderSource_func(shader, 1, (const GLchar **) &text, NULL);
+
+ glCompileShader_func(shader);
+
+ glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat);
+ if (!stat) {
+ GLchar log[1000];
+ GLsizei len;
+ glGetShaderInfoLog_func(shader, 1000, &len, log);
+ fprintf(stderr, "fslight: problem compiling shader:\n%s\n", log);
+ exit(1);
+ }
+}
+
+
+static void
+CheckLink(GLuint prog)
+{
+ GLint stat;
+ glGetProgramiv_func(prog, GL_LINK_STATUS, &stat);
+ if (!stat) {
+ GLchar log[1000];
+ GLsizei len;
+ glGetProgramInfoLog_func(prog, 1000, &len, log);
+ fprintf(stderr, "Linker error:\n%s\n", log);
+ }
+}
+
+
+static void
+Init(void)
+{
+ /* Fragment shader: compute distance of fragment from center of point
+ * (we're using texcoords but another varying could be used).
+ * if dist > 1, discard (coverage==0)
+ * if dist < k, coverage = 1
+ * else, coverage = func(dist)
+ * Note: length() uses sqrt() and may be expensive. The distance could
+ * be squared instead (with adjustments to the threshold (k) test)
+ */
+ static const char *fragShaderText =
+ "void main() {\n"
+ " float cover; \n"
+ " float k = 2.0 / gl_Point.size; \n"
+ " float d = length(gl_TexCoord[0].xy); \n"
+ " if (d >= 1.0) \n"
+ " discard; \n"
+ " if (d < 1.0 - k) \n"
+ " cover = 1.0; \n"
+ " else \n"
+ " cover = (1.0 - d) * 0.5 * gl_Point.size; \n"
+ " gl_FragColor.rgb = gl_Color.rgb; \n"
+ " gl_FragColor.a = cover; \n"
+ "}\n";
+ /* Vertex shader: compute new vertex position based on incoming vertex pos,
+ * texcoords, point size, and inverse viewport scale factor.
+ * Note: should compute point size attenuation here too.
+ */
+ static const char *vertShaderText =
+ "uniform vec2 viewportInv; \n"
+ "void main() {\n"
+ " vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
+ " gl_Position.xy = pos.xy + gl_MultiTexCoord0.xy * viewportInv \n"
+ " * gl_Point.size * pos.w; \n"
+ " gl_Position.zw = pos.zw; \n"
+ " gl_TexCoord[0] = gl_MultiTexCoord0; \n"
+ " gl_FrontColor = gl_Color; \n"
+ "}\n";
+ const char *version;
+
+ version = (const char *) glGetString(GL_VERSION);
+ if (version[0] != '2' || version[1] != '.') {
+ printf("This program requires OpenGL 2.x, found %s\n", version);
+ exit(1);
+ }
+ printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
+
+ GetExtensionFuncs();
+
+ FragShader = glCreateShader_func(GL_FRAGMENT_SHADER);
+ LoadAndCompileShader(FragShader, fragShaderText);
+
+ VertShader = glCreateShader_func(GL_VERTEX_SHADER);
+ LoadAndCompileShader(VertShader, vertShaderText);
+
+ Program = glCreateProgram_func();
+ glAttachShader_func(Program, FragShader);
+ glAttachShader_func(Program, VertShader);
+ glLinkProgram_func(Program);
+ CheckLink(Program);
+ glUseProgram_func(Program);
+
+ uViewportInv = glGetUniformLocation_func(Program, "viewportInv");
+
+ glUseProgram_func(0);
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowSize(WinWidth, WinHeight);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+ Win = glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutSpecialFunc(SpecialKey);
+ glutDisplayFunc(Redisplay);
+ Init();
+ glutMainLoop();
+ return 0;
+}
+
+
diff --git a/progs/glsl/trirast.c b/progs/glsl/trirast.c
new file mode 100644
index 0000000000..e4325deb1f
--- /dev/null
+++ b/progs/glsl/trirast.c
@@ -0,0 +1,326 @@
+/**
+ * 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"
+
+
+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)
+{
+ Zrot = glutGet(GLUT_ELAPSED_TIME) * 0.0005;
+ glutPostRedisplay();
+}
+
+
+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 27:
+ CleanUp();
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+LoadAndCompileShader(GLuint shader, const char *text)
+{
+ GLint stat;
+
+ glShaderSource_func(shader, 1, (const GLchar **) &text, NULL);
+
+ glCompileShader_func(shader);
+
+ glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat);
+ if (!stat) {
+ GLchar log[1000];
+ GLsizei len;
+ glGetShaderInfoLog_func(shader, 1000, &len, log);
+ fprintf(stderr, "fslight: problem compiling shader:\n%s\n", log);
+ exit(1);
+ }
+}
+
+
+/**
+ * Read a shader from a file.
+ */
+static void
+ReadShader(GLuint shader, const char *filename)
+{
+ const int max = 100*1000;
+ int n;
+ char *buffer = (char*) malloc(max);
+ FILE *f = fopen(filename, "r");
+ if (!f) {
+ fprintf(stderr, "fslight: Unable to open shader file %s\n", filename);
+ exit(1);
+ }
+
+ n = fread(buffer, 1, max, f);
+ printf("fslight: read %d bytes from shader file %s\n", n, filename);
+ if (n > 0) {
+ buffer[n] = 0;
+ LoadAndCompileShader(shader, buffer);
+ }
+
+ fclose(f);
+ free(buffer);
+}
+
+
+static void
+CheckLink(GLuint prog)
+{
+ GLint stat;
+ glGetProgramiv_func(prog, GL_LINK_STATUS, &stat);
+ if (!stat) {
+ GLchar log[1000];
+ GLsizei len;
+ glGetProgramInfoLog_func(prog, 1000, &len, log);
+ fprintf(stderr, "Linker error:\n%s\n", log);
+ }
+}
+
+
+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 = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
+ "}\n";
+ const char *version;
+
+ version = (const char *) glGetString(GL_VERSION);
+ if (version[0] != '2' || version[1] != '.') {
+ printf("This program requires OpenGL 2.x, found %s\n", version);
+ exit(1);
+ }
+
+ GetExtensionFuncs();
+
+ fragShader = glCreateShader_func(GL_FRAGMENT_SHADER);
+ if (FragProgFile)
+ ReadShader(fragShader, FragProgFile);
+ else
+ LoadAndCompileShader(fragShader, fragShaderText);
+
+ vertShader = glCreateShader_func(GL_VERTEX_SHADER);
+ if (VertProgFile)
+ ReadShader(vertShader, VertProgFile);
+ else
+ LoadAndCompileShader(vertShader, vertShaderText);
+
+ program = glCreateProgram_func();
+ glAttachShader_func(program, fragShader);
+ glAttachShader_func(program, vertShader);
+ glLinkProgram_func(program);
+ CheckLink(program);
+ 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;
+}