2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * See the COPYING file for license information.
18 * Guillaume Chazarain <booh@altern.org>
21 /***********************
22 * Texture management. *
23 ***********************/
27 #include <math.h> /* ceil() */
31 extern options_struct
*options
;
33 /* Lowest power of two bigger than the argument. */
34 G_GNUC_CONST
static guint
p2(guint p
)
44 /* Draws a piece of a multi-textures image or a whole mono-texture one. */
45 static void draw_rectangle(gdouble tex_x0
, gdouble tex_x1
,
46 gdouble tex_y0
, gdouble tex_y1
,
47 gdouble vert_x0
, gdouble vert_x1
,
48 gdouble vert_y0
, gdouble vert_y1
)
51 * (tex_x0 ; tex_y0) : Origin of the interesting part of the texture.
52 * (tex_x1 ; tex_y1) : Extremity of the interesting part of the texture.
53 * (vert_x0 ; vert_y0) : Origin of the rectangle.
54 * (vert_x1 ; vert_y1) : Extremity of the rectangle.
59 glTexCoord2d(tex_x0
, tex_y0
);
60 glVertex2d(vert_x0
, vert_y0
);
62 glTexCoord2d(tex_x1
, tex_y0
);
63 glVertex2d(vert_x1
, vert_y0
);
65 glTexCoord2d(tex_x1
, tex_y1
);
66 glVertex2d(vert_x1
, vert_y1
);
68 glTexCoord2d(tex_x0
, tex_y1
);
69 glVertex2d(vert_x0
, vert_y1
);
75 * The tiler was originally based on code from
76 * evas by Carsten Haitzler (The Rasterman).
80 * Called twice for each rectangle to get rectangle
81 * coordinates to put in the display list.
83 static void compute_coordinates(gliv_image
* im
,
84 gdouble
* vert0
, gdouble
* vert1
,
85 gdouble
* tex0
, gdouble
* tex1
,
86 gboolean is_x
, guint id
)
88 guint tiles
, left
, edge
;
93 tiles
= im
->init
->x_tiles
;
95 left
= im
->init
->x_left
;
96 edge
= im
->init
->x_edge
;
98 tiles
= im
->init
->y_tiles
;
100 left
= im
->init
->y_left
;
101 edge
= im
->init
->y_edge
;
104 if (id
!= tiles
- 1) {
105 *tex1
= (rt
->max_texture_size
- 2.0) / (rt
->max_texture_size
- 1.0);
108 *vert0
= -dim
/ 2.0 - 1.0;
109 *vert1
= *vert0
+ rt
->max_texture_size
- 1.0;
113 *vert0
= -dim
/ 2.0 + id
* (rt
->max_texture_size
- 2.0);
114 *vert1
= *vert0
+ rt
->max_texture_size
- 2.0;
115 *tex0
= 1.0 / (rt
->max_texture_size
+ 1.0);
116 *tex1
= (rt
->max_texture_size
- 2.0) / (rt
->max_texture_size
- 1.0);
124 *tex1
= (gdouble
) left
/ edge
;
127 *vert0
= -dim
/ 2.0 + id
* (rt
->max_texture_size
- 2.0);
128 *vert1
= dim
/ 2.0 - 1.0;
129 *tex0
= 1.0 / (edge
+ 1.0);
130 *tex1
= (left
- 1.0) / (edge
- 1.0);
134 * For some textures smaller than 128x128 there are problems.
135 * The code below shouldn't be needed but it doesn't hurt and
136 * it is a workaround for these problems.
138 ratio
= 128.0 / p2(dim
- id
* (rt
->max_texture_size
- 2));
146 static void rectangle(gliv_image
* im
, tile_dim
* tile
, guint i
, guint j
)
148 gdouble ty0
, ty1
, tx0
, tx1
;
149 gdouble x0
, x1
, y0
, y1
;
151 compute_coordinates(im
, &x0
, &x1
, &tx0
, &tx1
, TRUE
, i
);
152 compute_coordinates(im
, &y0
, &y1
, &ty0
, &ty1
, FALSE
, j
);
154 draw_rectangle(tx0
, tx1
, ty0
, ty1
, x0
, x1
, y0
, y1
);
156 /* Used when drawing, to know which tiles are hidden. */
163 /* Shortcut to OpenGL parameters common to all textures. */
164 static void texture_parameter(void)
166 /* These filters will be changed but it's important to initialize them. */
167 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
168 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
170 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
171 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
174 static void make_texture(gliv_image
* im
, guint i
, guint j
)
176 static GdkPixbuf
*tile_max_size
= NULL
;
179 gint x
, y
, w
, h
, gl_w
, gl_h
;
181 if (tile_max_size
== NULL
&& im
->nb_tiles
!= 1)
183 tile_max_size
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
, im
->has_alpha
, 8,
184 rt
->max_texture_size
,
185 rt
->max_texture_size
);
187 x
= i
* (rt
->max_texture_size
- 2);
188 y
= j
* (rt
->max_texture_size
- 2);
190 if (i
+ 1 == im
->init
->x_tiles
) {
191 /* Last horizontal tile. */
193 gl_w
= (gint
) p2((guint
) w
);
196 w
= gl_w
= rt
->max_texture_size
;
200 if (j
+ 1 == im
->init
->y_tiles
) {
201 /* Last vertical tile. */
203 gl_h
= (gint
) p2((guint
) h
);
206 h
= gl_h
= rt
->max_texture_size
;
213 * For some textures smaller than 128x128 there are problems.
214 * The code below shouldn't be needed but it doesn't hurt and
215 * it is a workaround for these problems.
217 gl_w
= CLAMP(gl_w
, 128, rt
->max_texture_size
);
218 gl_h
= CLAMP(gl_h
, 128, rt
->max_texture_size
);
220 if (gl_w
== rt
->max_texture_size
&& gl_h
== rt
->max_texture_size
&&
221 tile_max_size
!= NULL
)
223 tile
= tile_max_size
;
225 tile
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
, im
->has_alpha
, 8, gl_w
, gl_h
);
227 gdk_pixbuf_copy_area(im
->init
->im
, x
, y
, w
, h
, tile
, 0, 0);
230 /* Right border : copy the last column. */
231 gdk_pixbuf_copy_area(tile
, w
- 1, 0, 1, h
, tile
, w
, 0);
234 /* Lower corner : copy the last line. */
235 gdk_pixbuf_copy_area(tile
, 0, h
- 1, w
, 1, tile
, 0, h
);
238 /* Lower-right corner : copy the last pixel. */
239 gdk_pixbuf_copy_area(tile
, w
- 1, h
- 1, 1, 1, tile
, w
, h
);
242 glTexImage2D(GL_TEXTURE_2D
, 0, 3 + im
->has_alpha
, gl_w
, gl_h
, 0,
243 (im
->has_alpha
== TRUE
) ? GL_RGBA
: GL_RGB
, GL_UNSIGNED_BYTE
,
244 gdk_pixbuf_get_pixels(tile
));
246 if (tile
!= tile_max_size
)
247 gdk_pixbuf_unref(tile
);
249 if (last_tile
== TRUE
&& tile_max_size
!= NULL
) {
250 gdk_pixbuf_unref(tile_max_size
);
251 tile_max_size
= NULL
;
255 static void tiles_parameters(gliv_image
* im
, gboolean is_x
)
257 guint
*tiles
, *left
, *edge
;
261 tiles
= &im
->init
->x_tiles
;
262 left
= &im
->init
->x_left
;
263 edge
= &im
->init
->x_edge
;
266 tiles
= &im
->init
->y_tiles
;
267 left
= &im
->init
->y_left
;
268 edge
= &im
->init
->y_edge
;
275 *tiles
= (guint
) ceil((dim
- 2.0) / (rt
->max_texture_size
- 2.0));
277 *left
= dim
- (*tiles
- 1) * (rt
->max_texture_size
- 2);
282 static void compute_gl_dimensions(gliv_image
* im
)
284 tiles_parameters(im
, TRUE
);
285 tiles_parameters(im
, FALSE
);
287 im
->nb_tiles
= im
->init
->x_tiles
* im
->init
->y_tiles
;
289 im
->tex_ids
= g_new(guint
, im
->nb_tiles
);
290 glGenTextures(im
->nb_tiles
, im
->tex_ids
);
292 im
->list
= glGenLists(im
->nb_tiles
);
295 void create_display_list(gliv_image
* im
)
300 compute_gl_dimensions(im
);
302 im
->tiles
= g_new(tile_dim
, im
->nb_tiles
);
304 for (j
= 0; j
< im
->init
->y_tiles
; j
++)
305 for (i
= 0; i
< im
->init
->x_tiles
; i
++) {
306 glBindTexture(GL_TEXTURE_2D
, im
->tex_ids
[id
]);
307 make_texture(im
, i
, j
);
309 glNewList(im
->list
+ id
, GL_COMPILE
);
311 /* Redundant but need to be in the display list. */
312 glBindTexture(GL_TEXTURE_2D
, im
->tex_ids
[id
]);
314 rectangle(im
, im
->tiles
+ id
, i
, j
);