Add missing file image_format.h, and add grayscale support.
[movit] / input.cpp
1 #define GL_GLEXT_PROTOTYPES 1
2
3 #include <string.h>
4 #include <GL/gl.h>
5 #include <GL/glext.h>
6 #include <assert.h>
7
8 #include "input.h"
9 #include "util.h"
10
11 Input::Input(ImageFormat image_format, unsigned width, unsigned height)
12         : image_format(image_format),
13           needs_update(false),
14           use_srgb_texture_format(false),
15           needs_mipmaps(false),
16           width(width),
17           height(height)
18 {
19         register_int("use_srgb_texture_format", &use_srgb_texture_format);
20         register_int("needs_mipmaps", &needs_mipmaps);
21 }
22
23 void Input::finalize()
24 {
25         // Translate the input format to OpenGL's enums.
26         GLenum internal_format;
27         if (use_srgb_texture_format) {
28                 internal_format = GL_SRGB8;
29         } else {
30                 internal_format = GL_RGBA8;
31         }
32         if (image_format.pixel_format == FORMAT_RGB) {
33                 format = GL_RGB;
34                 bytes_per_pixel = 3;
35         } else if (image_format.pixel_format == FORMAT_RGBA) {
36                 format = GL_RGBA;
37                 bytes_per_pixel = 4;
38         } else if (image_format.pixel_format == FORMAT_BGR) {
39                 format = GL_BGR;
40                 bytes_per_pixel = 3;
41         } else if (image_format.pixel_format == FORMAT_BGRA) {
42                 format = GL_BGRA;
43                 bytes_per_pixel = 4;
44         } else if (image_format.pixel_format == FORMAT_GRAYSCALE) {
45                 format = GL_LUMINANCE;
46                 bytes_per_pixel = 1;
47         } else {
48                 assert(false);
49         }
50
51         // Create PBO to hold the texture holding the input image, and then the texture itself.
52         glGenBuffers(1, &pbo);
53         check_error();
54         glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
55         check_error();
56         glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, width * height * bytes_per_pixel, NULL, GL_STREAM_DRAW);
57         check_error();
58         glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
59         check_error();
60         
61         glGenTextures(1, &texture_num);
62         check_error();
63         glBindTexture(GL_TEXTURE_2D, texture_num);
64         check_error();
65         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
66         check_error();
67         // Intel/Mesa seems to have a broken glGenerateMipmap() for non-FBO textures, so do it here
68         // instead of calling glGenerateMipmap().
69         glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, needs_mipmaps);
70         check_error();
71         glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL);
72         check_error();
73
74         needs_update = false;
75 }
76         
77 void Input::set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num)
78 {
79         if (needs_update) {
80                 // Copy the pixel data into the PBO.
81                 glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
82                 check_error();
83                 void *mapped_pbo = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY);
84                 memcpy(mapped_pbo, pixel_data, width * height * bytes_per_pixel);
85                 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
86                 check_error();
87
88                 // Re-upload the texture from the PBO.
89                 glActiveTexture(GL_TEXTURE0);
90                 check_error();
91                 glBindTexture(GL_TEXTURE_2D, texture_num);
92                 check_error();
93                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
94                 check_error();
95                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
96                 check_error();
97                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
98                 check_error();
99                 glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
100                 check_error();
101
102                 needs_update = false;
103         }
104
105         // Bind it to a sampler.
106         set_uniform_int(glsl_program_num, prefix, "tex", *sampler_num);
107         ++*sampler_num;
108 }
109
110 std::string Input::output_fragment_shader()
111 {
112         return read_file("input.frag");
113 }