4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #define GL_GLEXT_PROTOTYPES
24 #include "bcsynchronous.h"
25 #include "bctexture.h"
26 #include "bcwindowbase.h"
27 #include "bccmodels.h"
30 BC_Texture::BC_Texture(int w, int h, int colormodel)
34 this->colormodel = colormodel;
38 texture_components = 0;
40 create_texture(w, h, colormodel);
44 BC_Texture::~BC_Texture()
49 void BC_Texture::clear_objects()
51 if(get_texture_id() >= 0)
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(
62 void BC_Texture::new_texture(BC_Texture **texture,
63 int w, int h, int colormodel)
66 (*texture) = new BC_Texture(w, h, colormodel);
69 (*texture)->create_texture(w, h, colormodel);
73 void BC_Texture::create_texture(int w, int h, int colormodel)
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);
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);
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);
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))
97 // printf("BC_Texture::create_texture released window_id=%d texture_id=%d\n",
98 // BC_WindowBase::get_synchronous()->current_window->get_id(),
100 BC_WindowBase::get_synchronous()->release_texture(
110 texture_components = new_components;
112 // Get matching texture
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.
118 window_id = BC_WindowBase::get_synchronous()->current_window->get_id();
121 // No matching texture exists.
122 // Create new texture with the proper dimensions
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);
137 glBindTexture(GL_TEXTURE_2D, (GLuint)texture_id);
138 glEnable(GL_TEXTURE_2D);
143 int BC_Texture::calculate_texture_size(int w, int *max)
146 for(i = 2; (max && i <= *max) || (!max && i < w); i *= 2)
154 if(max && i > *max) return 16;
158 int BC_Texture::get_texture_id()
163 int BC_Texture::get_texture_w()
168 int BC_Texture::get_texture_h()
173 int BC_Texture::get_texture_components()
175 return texture_components;
178 int BC_Texture::get_window_id()
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)
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);
199 void BC_Texture::bind(int texture_unit, int nearest)
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);
213 // GL_REPEAT in this case causes the upper left corners of the masks
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);
218 // Get the texture to alpha blend
219 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
226 static void write_ppm(uint8_t *tp, int w, int h, const char *fmt, ...)
228 va_list ap; va_start(ap, fmt);
229 char fn[256]; vsnprintf(fn, sizeof(fn), fmt, ap);
231 FILE *fp = !strcmp(fn,"-") ? stdout : fopen(fn,"w");
233 fprintf(fp,"P6\n%d %d\n255\n",w,h);
235 if( fp != stdout ) fclose(fp);
240 void BC_Texture::write_tex(const char *fn, int id)
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);
253 glActiveTexture(prev_id);
257 void BC_Texture::write_tex(const char *fn)