initial commit
[goodguy/history.git] / cinelerra-5.0 / 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_id = -1;
37         texture_w = 0;
38         texture_h = 0;
39         texture_components = 0;
40         window_id = -1;
41         create_texture(w, h, colormodel);
42 }
43
44
45 BC_Texture::~BC_Texture()
46 {
47         clear_objects();
48 }
49
50 void BC_Texture::clear_objects()
51 {
52         if(get_texture_id() >= 0)
53         {
54 // printf("VFrame::clear_objects %p window_id=%d texture_id=%d w=%d h=%d\n",
55 // this, window_id, texture_id, texture_w, texture_h);
56                 BC_WindowBase::get_synchronous()->release_texture(
57                         window_id,
58                         texture_id);
59                 texture_id = -1;
60         }
61 }
62
63 void BC_Texture::new_texture(BC_Texture **texture,
64         int w, int h, int colormodel)
65 {
66         if(!(*texture)) {
67                 (*texture) = new BC_Texture(w, h, colormodel);
68         }
69         else {
70                 (*texture)->create_texture(w, h, colormodel);
71         }
72 }
73
74 void BC_Texture::create_texture(int w, int h, int colormodel)
75 {
76 #ifdef HAVE_GL
77
78 // Get max texture size from the server.
79 // Maximum size was 4096 on the earliest cards that could do video.
80         int max_texture_size = 0;
81         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
82
83 // Calculate dimensions of texture
84         int new_w = calculate_texture_size(w, &max_texture_size);
85         int new_h = calculate_texture_size(h, &max_texture_size);
86         int new_components = BC_CModels::components(colormodel);
87
88         if(new_w < w || new_h < h) {
89                 printf("BC_Texture::create_texture frame size %dx%d bigger than maximum texture %dx%d.\n",
90                         w, h, max_texture_size, max_texture_size);
91         }
92
93 // Delete existing texture
94         if(texture_id >= 0 && (new_h != texture_h || new_w != texture_w ||
95                 new_components != texture_components ||
96                 BC_WindowBase::get_synchronous()->current_window->get_id() != window_id))
97         {
98 // printf("BC_Texture::create_texture released window_id=%d texture_id=%d\n",
99 // BC_WindowBase::get_synchronous()->current_window->get_id(),
100 // texture_id);
101                 BC_WindowBase::get_synchronous()->release_texture(
102                         window_id,
103                         texture_id);
104             texture_id = -1;
105             window_id = -1;
106         }
107
108
109         texture_w = new_w;
110         texture_h = new_h;
111         texture_components = new_components;
112
113 // Get matching texture
114         if(texture_id < 0) {
115                 texture_id = BC_WindowBase::get_synchronous()->get_texture(
116                         texture_w, texture_h, texture_components);
117 // A new VFrame has no window_id, so it must read it from the matching texture.
118                 if(texture_id >= 0)
119                         window_id = BC_WindowBase::get_synchronous()->current_window->get_id();
120         }
121
122 // No matching texture exists.
123 // Create new texture with the proper dimensions
124         if(texture_id < 0) {
125                 glGenTextures(1, (GLuint*)&texture_id);
126                 glBindTexture(GL_TEXTURE_2D, (GLuint)texture_id);
127                 glEnable(GL_TEXTURE_2D);
128                 if(texture_components == 4)
129                         glTexImage2D(GL_TEXTURE_2D, 0, 4, texture_w, texture_h,
130                                 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
131                 else
132                         glTexImage2D(GL_TEXTURE_2D, 0, 3, texture_w, texture_h,
133                                 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
134
135                 window_id = BC_WindowBase::get_synchronous()->current_window->get_id();
136                 BC_WindowBase::get_synchronous()->put_texture(texture_id,
137                         texture_w, texture_h, texture_components);
138 //printf("BC_Texture::new_texture created texture_id=%d window_id=%d w=%d h=%d\n",
139 // texture_id, window_id, texture_w, texture_h);
140         }
141         else {
142                 glBindTexture(GL_TEXTURE_2D, (GLuint)texture_id);
143                 glEnable(GL_TEXTURE_2D);
144         }
145 #endif
146 }
147
148 int BC_Texture::calculate_texture_size(int w, int *max)
149 {
150         int i;
151         for(i = 2; (max && i <= *max) || (!max && i < w); i *= 2)
152         {
153                 if(i >= w)
154                 {
155                         return i;
156                         break;
157                 }
158         }
159         if(max && i > *max) return 16;
160         return i;
161 }
162
163 int BC_Texture::get_texture_id()
164 {
165         return texture_id;
166 }
167
168 int BC_Texture::get_texture_w()
169 {
170         return texture_w;
171 }
172
173 int BC_Texture::get_texture_h()
174 {
175         return texture_h;
176 }
177
178 int BC_Texture::get_texture_components()
179 {
180         return texture_components;
181 }
182
183 int BC_Texture::get_window_id()
184 {
185         return window_id;
186 }
187
188
189 void BC_Texture::bind(int texture_unit)
190 {
191 #ifdef HAVE_GL
192 // Bind the texture
193         if(texture_id >= 0)
194         {
195                 if(texture_unit >= 0) glActiveTexture(GL_TEXTURE0 + texture_unit);
196                 glBindTexture(GL_TEXTURE_2D, texture_id);
197                 glEnable(GL_TEXTURE_2D);
198                 if(texture_unit >= 0)
199                 {
200                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
201                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
202
203 // GL_REPEAT in this case causes the upper left corners of the masks
204 // to blur.
205                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
206                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
207
208 // Get the texture to alpha blend
209                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
210                 }
211         }
212 #endif
213 }
214