Make combine_two_pixels() handle the fact that the GPU has limited subpixel interpola...
[movit] / init.cpp
1 #include "init.h"
2 #include "opengl.h"
3 #include "util.h"
4
5 bool movit_initialized = false;
6 float movit_texel_subpixel_precision;
7
8 namespace {
9
10 void measure_texel_subpixel_precision()
11 {
12         static const unsigned width = 1024;
13
14         // Generate a destination texture to render to, and an FBO.
15         GLuint dst_texnum, fbo;
16
17         glGenTextures(1, &dst_texnum);
18         check_error();
19         glBindTexture(GL_TEXTURE_2D, dst_texnum);
20         check_error();
21         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, width, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
22         check_error();
23
24         glGenFramebuffers(1, &fbo);
25         check_error();
26         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
27         check_error();
28         glFramebufferTexture2D(
29                 GL_FRAMEBUFFER,
30                 GL_COLOR_ATTACHMENT0,
31                 GL_TEXTURE_2D,
32                 dst_texnum,
33                 0);
34         check_error();
35
36         // Now generate a simple texture that's just [0,1].
37         GLuint src_texnum;
38         float texdata[] = { 0, 1 };
39         glGenTextures(1, &dst_texnum);
40         check_error();
41         glBindTexture(GL_TEXTURE_1D, dst_texnum);
42         check_error();
43         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
44         check_error();
45         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
46         check_error();
47         glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE16F_ARB, 2, 0, GL_LUMINANCE, GL_FLOAT, texdata);
48         check_error();
49         glEnable(GL_TEXTURE_1D);
50         check_error();
51
52         // Basic state.
53         glDisable(GL_BLEND);
54         check_error();
55         glDisable(GL_DEPTH_TEST);
56         check_error();
57         glDepthMask(GL_FALSE);
58         check_error();
59
60         glViewport(0, 0, width, 1);
61
62         glMatrixMode(GL_PROJECTION);
63         glLoadIdentity();
64         glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
65
66         glMatrixMode(GL_MODELVIEW);
67         glLoadIdentity();
68         check_error();
69
70         // Draw the texture stretched over a long quad, interpolating it out.
71         // Note that since the texel center is in (0.5), we need to adjust the
72         // texture coordinates in order not to get long stretches of (1,1,1,...)
73         // at the start and (...,0,0,0) at the end.
74         glBegin(GL_QUADS);
75
76         glTexCoord1f(0.25f);
77         glVertex2f(0.0f, 0.0f);
78
79         glTexCoord1f(0.75f);
80         glVertex2f(1.0f, 0.0f);
81
82         glTexCoord1f(0.75f);
83         glVertex2f(1.0f, 1.0f);
84
85         glTexCoord1f(0.25f);
86         glVertex2f(0.0f, 1.0f);
87
88         glEnd();
89         check_error();
90
91         glDisable(GL_TEXTURE_1D);
92         check_error();
93
94         // Now read the data back and see what the card did.
95         // (We only look at the red channel; the others will surely be the same.)
96         // We assume a linear ramp; anything else will give sort of odd results here.
97         float out_data[width];
98         glReadPixels(0, 0, width, 1, GL_RED, GL_FLOAT, out_data);
99         check_error();
100
101         float biggest_jump = 0.0f;
102         for (unsigned i = 1; i < width; ++i) {
103                 assert(out_data[i] >= out_data[i - 1]);
104                 biggest_jump = std::max(biggest_jump, out_data[i] - out_data[i - 1]);
105         }
106
107         movit_texel_subpixel_precision = biggest_jump;
108
109         // Clean up.
110         glBindTexture(GL_TEXTURE_1D, 0);
111         check_error();
112         glBindFramebuffer(GL_FRAMEBUFFER, 0);
113         check_error();
114         glDeleteFramebuffers(1, &fbo);
115         check_error();
116         glDeleteTextures(1, &dst_texnum);
117         check_error();
118         glDeleteTextures(1, &src_texnum);
119         check_error();
120 }
121
122 }  // namespace
123
124 void init_movit()
125 {
126         if (movit_initialized) {
127                 return;
128         }
129
130         // geez 
131         glPixelStorei(GL_PACK_ALIGNMENT, 1);
132         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
133
134         measure_texel_subpixel_precision();
135
136         movit_initialized = true;
137 }