camera position fix, rework transportque locks again, camera drag tweaks, window...
[goodguy/cinelerra.git] / cinelerra-5.1 / guicast / bctexture.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #define GL_GLEXT_PROTOTYPES
23
24 #include "bcsynchronous.h"
25 #include "bctexture.h"
26 #include "bcwindowbase.h"
27 #include "bccmodels.h"
28
29
30 BC_Texture::BC_Texture(int w, int h, int colormodel)
31 {
32         this->w = w;
33         this->h = h;
34         this->colormodel = colormodel;
35         texture_id = -1;
36         texture_w = 0;
37         texture_h = 0;
38         texture_components = 0;
39         window_id = -1;
40         create_texture(w, h, colormodel);
41 }
42
43
44 BC_Texture::~BC_Texture()
45 {
46         clear_objects();
47 }
48
49 void BC_Texture::clear_objects()
50 {
51         if(get_texture_id() >= 0)
52         {
53 // printf("VFrame::clear_objects %p window_id=%d texture_id=%d w=%d h=%d\n",
54 // this, window_id, texture_id, texture_w, texture_h);
55                 BC_WindowBase::get_synchronous()->release_texture(
56                         window_id,
57                         texture_id);
58                 texture_id = -1;
59         }
60 }
61
62 void BC_Texture::new_texture(BC_Texture **texture,
63         int w, int h, int colormodel)
64 {
65         if(!(*texture)) {
66                 (*texture) = new BC_Texture(w, h, colormodel);
67         }
68         else {
69                 (*texture)->create_texture(w, h, colormodel);
70         }
71 }
72
73 void BC_Texture::create_texture(int w, int h, int colormodel)
74 {
75 #ifdef HAVE_GL
76
77 // Get max texture size from the server.
78 // Maximum size was 4096 on the earliest cards that could do video.
79         int max_texture_size = 0;
80         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
81
82 // Calculate dimensions of texture
83         int new_w = calculate_texture_size(w, &max_texture_size);
84         int new_h = calculate_texture_size(h, &max_texture_size);
85         int new_components = BC_CModels::components(colormodel);
86
87         if(new_w < w || new_h < h) {
88                 printf("BC_Texture::create_texture frame size %dx%d bigger than maximum texture %dx%d.\n",
89                         w, h, max_texture_size, max_texture_size);
90         }
91
92 // Delete existing texture
93         if(texture_id >= 0 && (new_h != texture_h || new_w != texture_w ||
94                 new_components != texture_components ||
95                 BC_WindowBase::get_synchronous()->current_window->get_id() != window_id))
96         {
97 // printf("BC_Texture::create_texture released window_id=%d texture_id=%d\n",
98 // BC_WindowBase::get_synchronous()->current_window->get_id(),
99 // texture_id);
100                 BC_WindowBase::get_synchronous()->release_texture(
101                         window_id,
102                         texture_id);
103             texture_id = -1;
104             window_id = -1;
105         }
106
107
108         texture_w = new_w;
109         texture_h = new_h;
110         texture_components = new_components;
111
112 // Get matching texture
113         if(texture_id < 0) {
114                 texture_id = BC_WindowBase::get_synchronous()->get_texture(
115                         texture_w, texture_h, texture_components);
116 // A new VFrame has no window_id, so it must read it from the matching texture.
117                 if(texture_id >= 0)
118                         window_id = BC_WindowBase::get_synchronous()->current_window->get_id();
119         }
120
121 // No matching texture exists.
122 // Create new texture with the proper dimensions
123         if(texture_id < 0) {
124                 glGenTextures(1, (GLuint*)&texture_id);
125                 glBindTexture(GL_TEXTURE_2D, (GLuint)texture_id);
126                 glEnable(GL_TEXTURE_2D);
127                 if(texture_components == 4)
128                         glTexImage2D(GL_TEXTURE_2D, 0, 4, texture_w, texture_h,
129                                 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
130                 else
131                         glTexImage2D(GL_TEXTURE_2D, 0, 3, texture_w, texture_h,
132                                 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
133
134                 window_id = BC_WindowBase::get_synchronous()->current_window->get_id();
135                 BC_WindowBase::get_synchronous()->put_texture(texture_id,
136                         texture_w, texture_h, texture_components);
137 //printf("BC_Texture::new_texture created texture_id=%d window_id=%d w=%d h=%d\n",
138 // texture_id, window_id, texture_w, texture_h);
139         }
140         else {
141                 glBindTexture(GL_TEXTURE_2D, (GLuint)texture_id);
142                 glEnable(GL_TEXTURE_2D);
143         }
144 #endif
145 }
146
147 int BC_Texture::calculate_texture_size(int w, int *max)
148 {
149         int i;
150         for(i = 2; (max && i <= *max) || (!max && i < w); i *= 2)
151         {
152                 if(i >= w)
153                 {
154                         return i;
155                         break;
156                 }
157         }
158         if(max && i > *max) return 16;
159         return i;
160 }
161
162 int BC_Texture::get_texture_id()
163 {
164         return texture_id;
165 }
166
167 int BC_Texture::get_texture_w()
168 {
169         return texture_w;
170 }
171
172 int BC_Texture::get_texture_h()
173 {
174         return texture_h;
175 }
176
177 int BC_Texture::get_texture_components()
178 {
179         return texture_components;
180 }
181
182 int BC_Texture::get_window_id()
183 {
184         return window_id;
185 }
186
187
188 void BC_Texture::draw_texture(
189         float in_x1, float in_y1, float in_x2, float in_y2,
190         float out_x1, float out_y1, float out_x2, float out_y2)
191 {
192 #ifdef HAVE_GL
193         glBegin(GL_QUADS);
194         glNormal3f(0, 0, 1.0);
195         glTexCoord2f(in_x1, in_y1);   glVertex3f(out_x1, out_y1, 0);
196         glTexCoord2f(in_x2, in_y1);   glVertex3f(out_x2, out_y1, 0);
197         glTexCoord2f(in_x2, in_y2);   glVertex3f(out_x2, out_y2, 0);
198         glTexCoord2f(in_x1, in_y2);   glVertex3f(out_x1, out_y2, 0);
199         glEnd();
200 #endif
201 }
202
203 void BC_Texture::bind(int texture_unit)
204 {
205 #ifdef HAVE_GL
206 // Bind the texture
207         if(texture_id >= 0)
208         {
209                 if(texture_unit >= 0) glActiveTexture(GL_TEXTURE0 + texture_unit);
210                 glBindTexture(GL_TEXTURE_2D, texture_id);
211                 glEnable(GL_TEXTURE_2D);
212                 if(texture_unit >= 0)
213                 {
214                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
215                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
216
217 // GL_REPEAT in this case causes the upper left corners of the masks
218 // to blur.
219                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
220                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
221
222 // Get the texture to alpha blend
223                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
224                 }
225         }
226 #endif
227 }
228
229 #ifdef HAVE_GL
230 static void write_ppm(uint8_t *tp, int w, int h, const char *fmt, ...)
231 {
232   va_list ap;    va_start(ap, fmt);
233   char fn[256];  vsnprintf(fn, sizeof(fn), fmt, ap);
234   va_end(ap);
235   FILE *fp = !strcmp(fn,"-") ? stdout : fopen(fn,"w");
236   if( fp ) {
237     fprintf(fp,"P6\n%d %d\n255\n",w,h);
238     fwrite(tp,3*w,h,fp);
239     if( fp != stdout ) fclose(fp);
240   }
241 }
242 #endif
243
244 void BC_Texture::write_tex(const char *fn)
245 {
246 #ifdef HAVE_GL
247         int prev_id = -1;
248         glGetIntegerv(GL_ACTIVE_TEXTURE, &prev_id);
249         glActiveTexture(GL_TEXTURE31);
250         glBindTexture(GL_TEXTURE_2D, texture_id);
251         glEnable(GL_TEXTURE_2D);
252         int w = get_texture_w(), h = get_texture_h();
253         uint8_t *img = new uint8_t[w*h*3];
254         glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
255         write_ppm(img, w, h, "%s", fn);
256         delete img;
257         glActiveTexture(prev_id);
258 #endif
259 }
260
261