9569df193418dfb603e480c25d3e55b35351d6c6
[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         reshape_pending = redisp_pending = 1;
103
104         glGenTextures(1, &fbtex);
105         glBindTexture(GL_TEXTURE_2D, fbtex);
106         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
107         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
108
109 #ifdef __unix__
110         dpy = glXGetCurrentDisplay();
111         xfd = ConnectionNumber(dpy);
112         maxfd = xfd > pfd[0] ? xfd : pfd[0];
113
114         while(!quit) {
115                 struct timeval tv = {0, 0};
116                 fd_set rdset;
117
118                 FD_ZERO(&rdset);
119                 FD_SET(xfd, &rdset);
120                 FD_SET(pfd[0], &rdset);
121
122                 if(select(maxfd + 1, &rdset, 0, 0, redisp_pending ? &tv : 0) == -1) {
123                         if(errno == EINTR) continue;
124                         fprintf(stderr, "select failed: %s\n", strerror(errno));
125                         break;
126                 }
127
128                 redisp_pending = 0;
129                 glutMainLoopEvent();
130
131                 if(FD_ISSET(pfd[0], &rdset)) {
132                         struct erb_rect rect;
133                         read(pfd[0], &rect, sizeof rect);
134                         glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x, rect.y, rect.w, rect.h,
135                                         GL_RGBA, GL_FLOAT, erb_getframe(erb) + (rect.y * win_width + rect.x) * 4);
136                         post_redisplay();
137                         printf("update (%d %d %dx%d)!\n", rect.x, rect.y, rect.w, rect.h);
138                 }
139         }
140 #endif  /* __unix__ */
141
142         erb_destroy(erb);
143         return 0;
144 }
145
146 static void jobdone(unsigned int job, struct erb_rect *rect, void *cls)
147 {
148         printf("jobdone!\n");
149         write(pfd[1], rect, sizeof *rect);
150 }
151
152 static void display(void)
153 {
154         if(reshape_pending) {
155                 reshape_pending = 0;
156
157                 erb_allocframe(erb, win_width, win_height);
158                 erb_begin(erb);
159
160                 glPixelStorei(GL_UNPACK_ROW_LENGTH, win_width);
161
162                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, win_width, win_height, 0,
163                                 GL_RGBA, GL_FLOAT, erb_getframe(erb));
164         }
165
166         glClear(GL_COLOR_BUFFER_BIT);
167
168         glUseProgram(sdr);
169
170         glBegin(GL_QUADS);
171         glColor3f(1, 1, 1);
172         glTexCoord2f(0, 0);
173         glVertex2f(0, 0);
174         glTexCoord2f(1, 0);
175         glVertex2f(win_width, 0);
176         glTexCoord2f(1, 1);
177         glVertex2f(win_width, win_height);
178         glTexCoord2f(0, 1);
179         glVertex2f(0, win_height);
180         glEnd();
181
182         if(drag) {
183                 glUseProgram(0);
184
185                 glEnable(GL_LOGIC_OP);
186                 glLogicOp(GL_XOR);
187
188                 glBegin(GL_LINE_LOOP);
189                 glColor3f(1, 1, 1);
190                 glVertex2f(drag_x, drag_y);
191                 glVertex2f(mouse_x, drag_y);
192                 glVertex2f(mouse_x, mouse_y);
193                 glVertex2f(drag_x, mouse_y);
194                 glEnd();
195
196                 glDisable(GL_LOGIC_OP);
197         }
198
199         glutSwapBuffers();
200 }
201
202 static void reshape(int x, int y)
203 {
204         win_width = x;
205         win_height = y;
206         win_aspect = (float)x / (float)y;
207
208         glViewport(0, 0, x, y);
209
210         glMatrixMode(GL_PROJECTION);
211         glLoadIdentity();
212         glOrtho(0, x, y, 0, -1, 1);
213
214         reshape_pending = 1;
215         post_redisplay();
216 }
217
218 static void keyb(unsigned char key, int x, int y)
219 {
220         if(key == 27) {
221                 glutExit();
222                 quit = 1;
223         }
224         post_redisplay();
225 }
226
227 static void mouse(int bn, int st, int x, int y)
228 {
229         int rect[4];
230
231         mouse_x = x;
232         mouse_y = y;
233
234         if(bn == 0) {
235                 if(st == GLUT_DOWN) {
236                         drag = 1;
237                         drag_x = x;
238                         drag_y = y;
239                 } else {
240                         if(drag) {
241                                 drag = 0;
242
243                                 rect[0] = x < drag_x ? x : drag_x;
244                                 rect[1] = y < drag_y ? y : drag_y;
245                                 rect[2] = abs(x - drag_x);
246                                 rect[3] = abs(y - drag_y);
247
248                                 erb_queue_block(erb, 0, rect[0], rect[1], rect[2], rect[3]);
249                                 printf("rect: %d,%d %dx%d\n", rect[0], rect[1], rect[2], rect[3]);
250                         }
251                 }
252
253                 post_redisplay();
254         }
255         if(bn == 2 && st == GLUT_DOWN) {
256                 drag = 0;
257                 post_redisplay();
258         }
259 }
260
261 static void motion(int x, int y)
262 {
263         mouse_x = x;
264         mouse_y = y;
265
266         post_redisplay();
267 }