working on the transformation node system
[erebus2020] / xerebus / src / main.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <errno.h>
4 #include "opengl.h"
5 #include <GL/freeglut.h>
6 #include "erebus.h"
7 #include "sdr.h"
8
9 #ifdef __unix__
10 #include <unistd.h>
11 #include <sys/select.h>
12 #include <X11/Xlib.h>
13 #include <GL/glx.h>
14
15 static Display *dpy;
16 static int pfd[2];
17 #endif
18
19 #define post_redisplay()  do { glutPostRedisplay(); redisp_pending = 1; } while(0)
20
21 static void jobdone(unsigned int job, struct erb_rect *rect, void *cls);
22 static void display(void);
23 static void reshape(int x, int y);
24 static void keyb(unsigned char key, int x, int y);
25 static void mouse(int bn, int st, int x, int y);
26 static void motion(int x, int y);
27
28 static void dummy_idle(void) {}
29
30 static int win_width, win_height;
31 static float win_aspect;
32 static int reshape_pending, redisp_pending;
33 static int quit;
34
35 static struct erb_rend *erb;
36
37 static int mouse_x, mouse_y;
38 static int drag_x, drag_y;
39 static int drag;
40
41 static float disp_gamma = 2.2f;
42
43 static unsigned int fbtex;
44 static unsigned int sdr;
45
46 static const char *vs_src =
47         "void main()\n"
48         "{\n"
49         "       gl_Position = ftransform();\n"
50         "       gl_TexCoord[0] = gl_MultiTexCoord0;\n"
51         "}\n";
52
53 static const char *ps_src =
54         "uniform sampler2D tex;\n"
55         "uniform float inv_gamma;\n"
56         "\n"
57         "void main()\n"
58         "{\n"
59         "       vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n"
60         "       gl_FragColor.rgb = pow(texel.xyz / texel.w, vec3(inv_gamma));\n"
61         "       gl_FragColor.a = 1.0;\n"
62         "}\n";
63
64
65 int main(int argc, char **argv)
66 {
67         unsigned int vs, ps;
68
69 #ifdef __unix__
70         int xfd, maxfd;
71
72         pipe(pfd);
73 #endif
74
75         glutInit(&argc, argv);
76         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
77         glutInitWindowSize(1280, 800);
78         glutCreateWindow("X erebus");
79
80         glutDisplayFunc(display);
81         glutIdleFunc(dummy_idle);       /* we want to be blocking in select, not in glutMainLoopEvent */
82         glutReshapeFunc(reshape);
83         glutKeyboardFunc(keyb);
84         glutMouseFunc(mouse);
85         glutMotionFunc(motion);
86
87         if(!(vs = create_vertex_shader(vs_src))) {
88                 return 1;
89         }
90         if(!(ps = create_pixel_shader(ps_src))) {
91                 return 1;
92         }
93         if(!(sdr = create_program_link(vs, ps, 0))) {
94                 return 1;
95         }
96         set_uniform_float(sdr, "inv_gamma", 1.0f / disp_gamma);
97
98         if(!(erb = erb_create())) {
99                 return 1;
100         }
101         erb_set_done_callback(erb, jobdone, 0);
102
103         reshape_pending = redisp_pending = 1;
104
105         glGenTextures(1, &fbtex);
106         glBindTexture(GL_TEXTURE_2D, fbtex);
107         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
108         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
109
110 #ifdef __unix__
111         dpy = glXGetCurrentDisplay();
112         xfd = ConnectionNumber(dpy);
113         maxfd = xfd > pfd[0] ? xfd : pfd[0];
114
115         while(!quit) {
116                 struct timeval tv = {0, 0};
117                 fd_set rdset;
118
119                 FD_ZERO(&rdset);
120                 FD_SET(xfd, &rdset);
121                 FD_SET(pfd[0], &rdset);
122
123                 if(select(maxfd + 1, &rdset, 0, 0, redisp_pending ? &tv : 0) == -1) {
124                         if(errno == EINTR) continue;
125                         fprintf(stderr, "select failed: %s\n", strerror(errno));
126                         break;
127                 }
128
129                 if(FD_ISSET(pfd[0], &rdset)) {
130                         struct erb_rect rect;
131                         read(pfd[0], &rect, sizeof rect);
132                         glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x, rect.y, rect.w, rect.h,
133                                         GL_RGBA, GL_FLOAT, erb_getframe(erb) + (rect.y * win_width + rect.x) * 4);
134                         post_redisplay();
135                 }
136
137                 if(FD_ISSET(xfd, &rdset) || redisp_pending) {
138                         redisp_pending = 0;
139                         glutMainLoopEvent();
140                 }
141         }
142 #endif  /* __unix__ */
143
144         erb_destroy(erb);
145         return 0;
146 }
147
148 static void jobdone(unsigned int job, struct erb_rect *rect, void *cls)
149 {
150         write(pfd[1], rect, sizeof *rect);
151 }
152
153 static void display(void)
154 {
155         if(reshape_pending) {
156                 reshape_pending = 0;
157
158                 erb_allocframe(erb, win_width, win_height);
159                 erb_begin(erb);
160
161                 glPixelStorei(GL_UNPACK_ROW_LENGTH, win_width);
162
163                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, win_width, win_height, 0,
164                                 GL_RGBA, GL_FLOAT, erb_getframe(erb));
165         }
166
167         glClear(GL_COLOR_BUFFER_BIT);
168
169         glUseProgram(sdr);
170
171         glBegin(GL_QUADS);
172         glColor3f(1, 1, 1);
173         glTexCoord2f(0, 0);
174         glVertex2f(0, 0);
175         glTexCoord2f(1, 0);
176         glVertex2f(win_width, 0);
177         glTexCoord2f(1, 1);
178         glVertex2f(win_width, win_height);
179         glTexCoord2f(0, 1);
180         glVertex2f(0, win_height);
181         glEnd();
182
183         if(drag) {
184                 glUseProgram(0);
185
186                 glEnable(GL_LOGIC_OP);
187                 glLogicOp(GL_XOR);
188
189                 glBegin(GL_LINE_LOOP);
190                 glColor3f(1, 1, 1);
191                 glVertex2f(drag_x, drag_y);
192                 glVertex2f(mouse_x, drag_y);
193                 glVertex2f(mouse_x, mouse_y);
194                 glVertex2f(drag_x, mouse_y);
195                 glEnd();
196
197                 glDisable(GL_LOGIC_OP);
198         }
199
200         glutSwapBuffers();
201 }
202
203 static void reshape(int x, int y)
204 {
205         win_width = x;
206         win_height = y;
207         win_aspect = (float)x / (float)y;
208
209         glViewport(0, 0, x, y);
210
211         glMatrixMode(GL_PROJECTION);
212         glLoadIdentity();
213         glOrtho(0, x, y, 0, -1, 1);
214
215         reshape_pending = 1;
216         post_redisplay();
217 }
218
219 static void keyb(unsigned char key, int x, int y)
220 {
221         if(key == 27) {
222                 glutExit();
223                 quit = 1;
224         }
225         post_redisplay();
226 }
227
228 static void mouse(int bn, int st, int x, int y)
229 {
230         int rect[4];
231
232         mouse_x = x;
233         mouse_y = y;
234
235         if(bn == 0) {
236                 if(st == GLUT_DOWN) {
237                         drag = 1;
238                         drag_x = x;
239                         drag_y = y;
240                 } else {
241                         if(drag) {
242                                 drag = 0;
243
244                                 rect[0] = x < drag_x ? x : drag_x;
245                                 rect[1] = y < drag_y ? y : drag_y;
246                                 rect[2] = abs(x - drag_x);
247                                 rect[3] = abs(y - drag_y);
248
249                                 erb_queue_block(erb, 0, rect[0], rect[1], rect[2], rect[3]);
250                                 printf("rect: %d,%d %dx%d\n", rect[0], rect[1], rect[2], rect[3]);
251                         }
252                 }
253
254                 post_redisplay();
255         }
256         if(bn == 2 && st == GLUT_DOWN) {
257                 drag = 0;
258                 post_redisplay();
259         }
260 }
261
262 static void motion(int x, int y)
263 {
264         mouse_x = x;
265         mouse_y = y;
266
267         post_redisplay();
268 }