fix make_shader segment count, repair mask tweak keyfrm updates for xlat,rotate,scale
[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                 int internal_format = texture_components == 4 ? GL_RGBA8 : GL_RGB8 ;
128                 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture_w, texture_h,
129                                 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
130                 window_id = BC_WindowBase::get_synchronous()->current_window->get_id();
131                 BC_WindowBase::get_synchronous()->put_texture(texture_id,
132                         texture_w, texture_h, texture_components);
133 //printf("BC_Texture::new_texture created texture_id=%d window_id=%d w=%d h=%d\n",
134 // texture_id, window_id, texture_w, texture_h);
135         }
136         else {
137                 glBindTexture(GL_TEXTURE_2D, (GLuint)texture_id);
138                 glEnable(GL_TEXTURE_2D);
139         }
140 #endif
141 }
142
143 int BC_Texture::calculate_texture_size(int w, int *max)
144 {
145         int i;
146         for(i = 2; (max && i <= *max) || (!max && i < w); i *= 2)
147         {
148                 if(i >= w)
149                 {
150                         return i;
151                         break;
152                 }
153         }
154         if(max && i > *max) return 16;
155         return i;
156 }
157
158 int BC_Texture::get_texture_id()
159 {
160         return texture_id;
161 }
162
163 int BC_Texture::get_texture_w()
164 {
165         return texture_w;
166 }
167
168 int BC_Texture::get_texture_h()
169 {
170         return texture_h;
171 }
172
173 int BC_Texture::get_texture_components()
174 {
175         return texture_components;
176 }
177
178 int BC_Texture::get_window_id()
179 {
180         return window_id;
181 }
182
183
184 void BC_Texture::draw_texture(
185         float in_x1, float in_y1, float in_x2, float in_y2,
186         float out_x1, float out_y1, float out_x2, float out_y2)
187 {
188 #ifdef HAVE_GL
189         glBegin(GL_QUADS);
190         glNormal3f(0, 0, 1.0);
191         glTexCoord2f(in_x1, in_y1);   glVertex3f(out_x1, out_y1, 0);
192         glTexCoord2f(in_x2, in_y1);   glVertex3f(out_x2, out_y1, 0);
193         glTexCoord2f(in_x2, in_y2);   glVertex3f(out_x2, out_y2, 0);
194         glTexCoord2f(in_x1, in_y2);   glVertex3f(out_x1, out_y2, 0);
195         glEnd();
196 #endif
197 }
198
199 void BC_Texture::bind(int texture_unit, int nearest)
200 {
201 #ifdef HAVE_GL
202 // Bind the texture
203         if(texture_id >= 0)
204         {
205                 if(texture_unit >= 0) glActiveTexture(GL_TEXTURE0 + texture_unit);
206                 glBindTexture(GL_TEXTURE_2D, texture_id);
207                 glEnable(GL_TEXTURE_2D);
208                 if(texture_unit >= 0) {
209                         int filter = nearest ? GL_NEAREST : GL_LINEAR;
210                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
211                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
212
213 // GL_REPEAT in this case causes the upper left corners of the masks
214 // to blur.
215                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
216                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
217
218 // Get the texture to alpha blend
219                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
220                 }
221         }
222 #endif
223 }
224
225 #ifdef HAVE_GL
226 static void write_ppm(uint8_t *tp, int w, int h, const char *fmt, ...)
227 {
228   va_list ap;    va_start(ap, fmt);
229   char fn[256];  vsnprintf(fn, sizeof(fn), fmt, ap);
230   va_end(ap);
231   FILE *fp = !strcmp(fn,"-") ? stdout : fopen(fn,"w");
232   if( fp ) {
233     fprintf(fp,"P6\n%d %d\n255\n",w,h);
234     fwrite(tp,3*w,h,fp);
235     if( fp != stdout ) fclose(fp);
236   }
237 }
238 #endif
239
240 void BC_Texture::write_tex(const char *fn, int id)
241 {
242 #ifdef HAVE_GL
243         int prev_id = -1;
244         glGetIntegerv(GL_ACTIVE_TEXTURE, &prev_id);
245         glActiveTexture(GL_TEXTURE0+id);
246         glBindTexture(GL_TEXTURE_2D, texture_id);
247         glEnable(GL_TEXTURE_2D);
248         int w = get_texture_w(), h = get_texture_h();
249         uint8_t *img = new uint8_t[w*h*3];
250         glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
251         write_ppm(img, w, h, "%s", fn);
252         delete img;
253         glActiveTexture(prev_id);
254 #endif
255 }
256
257 void BC_Texture::write_tex(const char *fn)
258 {
259 #ifdef HAVE_GL
260         write_tex(fn, 31);
261 #endif
262 }
263