initial commit
[meshfrac] / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include "opengl.h"
5 #include <GL/glut.h>
6 #include <cgmath/cgmath.h>
7 #include "cmesh.h"
8 #include "meshgen.h"
9 #include "sdr.h"
10
11 static const char *vsdr_src =
12         "varying vec3 v_norm, v_ldir, v_vdir;\n"
13         "void main()\n"
14         "{\n"
15         "       gl_Position = ftransform();\n"
16         "       vec3 vpos = (gl_ModelViewMatrix * gl_Vertex).xyz;\n"
17         "       v_vdir = -vpos;\n"
18         "       v_norm = gl_NormalMatrix * gl_Normal;\n"
19         "       v_ldir = gl_LightSource[0].position.xyz - vpos;\n"
20         "}\n";
21
22 static const char *psdr_src =
23         "varying vec3 v_norm, v_ldir, v_vdir;\n"
24         "void main()\n"
25         "{\n"
26         "       vec3 n = normalize(v_norm);\n"
27         "       vec3 v = normalize(v_vdir);\n"
28         "       vec3 l = normalize(v_ldir);\n"
29         "       vec3 h = normalize(v + l);\n"
30         "       float ndotl = max(dot(n, l), 0.0);\n"
31         "       float ndoth = max(dot(n, h), 0.0);\n"
32         "       float spec = pow(ndoth, gl_FrontMaterial.shininess);\n"
33         "       vec3 dcol = gl_FrontMaterial.diffuse.rgb * ndotl;\n"
34         "       vec3 scol = gl_FrontMaterial.specular.rgb * spec;\n"
35         "       gl_FragColor = vec4(dcol + scol, 1.0);\n"
36         "}\n";
37
38 static int init(void);
39 static void cleanup(void);
40 static void display(void);
41 static void reshape(int x, int y);
42 static void keydown(unsigned char key, int x, int y);
43 static void mouse(int bn, int st, int x, int y);
44 static void motion(int x, int y);
45
46 static int win_width, win_height;
47 static cgm_vec3 view_pos;
48 static float view_theta, view_phi = 0.6, view_dist = 8;
49 static float proj_mat[16], view_mat[16];
50 static int bnstate[8];
51 static int mx, my;
52
53 static struct cmesh *mesh;
54 static unsigned int sdr;
55
56 int main(int argc, char **argv)
57 {
58         glutInit(&argc, argv);
59         glutInitWindowSize(1280, 800);
60         glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
61         glutCreateWindow("meshfrac");
62
63         glutDisplayFunc(display);
64         glutReshapeFunc(reshape);
65         glutKeyboardFunc(keydown);
66         glutMouseFunc(mouse);
67         glutMotionFunc(motion);
68
69         if(init() == -1) {
70                 return 1;
71         }
72         atexit(cleanup);
73
74         glutMainLoop();
75         return 0;
76 }
77
78 static int init(void)
79 {
80         unsigned int vsdr, psdr;
81         float diffuse[] = {0.2, 0.3, 0.8, 1};
82         float specular[] = {0.8, 0.8, 0.8, 1};
83 #ifdef __glew_h__
84         glewInit();
85 #endif
86
87         if(!(vsdr = create_vertex_shader(vsdr_src))) {
88                 return -1;
89         }
90         if(!(psdr = create_pixel_shader(psdr_src))) {
91                 free_shader(vsdr);
92                 return -1;
93         }
94         if(!(sdr = create_program_link(vsdr, psdr, 0))) {
95                 free_shader(vsdr);
96                 free_shader(psdr);
97                 return -1;
98         }
99
100         glEnable(GL_CULL_FACE);
101         glEnable(GL_DEPTH_TEST);
102         glEnable(GL_LIGHTING);
103         glEnable(GL_LIGHT0);
104
105         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, diffuse);
106         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
107         glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 60);
108
109         bind_program(sdr);
110
111         mesh = cmesh_alloc();
112         gen_torus(mesh, 2, 0.8, 24, 12, 1, 1);
113
114         return 0;
115 }
116
117 static void cleanup(void)
118 {
119         cmesh_free(mesh);
120         free_program(sdr);
121 }
122
123 static void display(void)
124 {
125         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
126
127         cgm_mtranslation(view_mat, 0, 0, -view_dist);
128         cgm_mprerotate_x(view_mat, view_phi);
129         cgm_mprerotate_y(view_mat, view_theta);
130         cgm_mpretranslate(view_mat, -view_pos.x, -view_pos.y, -view_pos.z);
131         glMatrixMode(GL_MODELVIEW);
132         glLoadMatrixf(view_mat);
133
134         cmesh_draw(mesh);
135
136         assert(glGetError() == GL_NO_ERROR);
137         glutSwapBuffers();
138 }
139
140 static void reshape(int x, int y)
141 {
142         win_width = x;
143         win_height = y;
144         glViewport(0, 0, x, y);
145
146         cgm_mperspective(proj_mat, cgm_deg_to_rad(50), (float)x / y, 0.5, 500.0);
147         glMatrixMode(GL_PROJECTION);
148         glLoadMatrixf(proj_mat);
149 }
150
151 static void keydown(unsigned char key, int x, int y)
152 {
153         switch(key) {
154         case 27:
155                 exit(0);
156         }
157 }
158
159 static void mouse(int bn, int st, int x, int y)
160 {
161         int bidx = bn - GLUT_LEFT_BUTTON;
162         if(bidx < 8) {
163                 bnstate[bidx] = st == GLUT_DOWN;
164         }
165         mx = x;
166         my = y;
167 }
168
169 static void motion(int x, int y)
170 {
171         int dx = x - mx;
172         int dy = y - my;
173         mx = x;
174         my = y;
175
176         if(!(dx | dy)) return;
177
178         if(bnstate[0]) {
179                 view_theta += cgm_deg_to_rad(dx * 0.5);
180                 view_phi += cgm_deg_to_rad(dy * 0.5);
181                 if(view_phi < -M_PI / 2) view_phi = -M_PI / 2;
182                 if(view_phi > M_PI / 2) view_phi = M_PI / 2;
183                 glutPostRedisplay();
184         }
185         if(bnstate[1]) {
186                 cgm_vec3 up, right;
187
188                 up.x = -sin(view_theta) * sin(view_phi);
189                 up.y = -cos(view_phi);
190                 up.z = cos(view_theta) * sin(view_phi);
191                 right.x = cos(view_theta);
192                 right.y = 0;
193                 right.z = sin(view_theta);
194
195                 view_pos.x -= (right.x * dx + up.x * dy) * 0.01;
196                 view_pos.y -= up.y * dy * 0.01;
197                 view_pos.z -= (right.z * dx + up.z * dy) * 0.01;
198                 glutPostRedisplay();
199         }
200         if(bnstate[2]) {
201                 view_dist += dy * 0.1;
202                 if(view_dist < 0) view_dist = 0;
203                 glutPostRedisplay();
204         }
205 }