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 <guichaz@yahoo.fr>
21 /***********************
22 * Rendering functions *
23 ***********************/
25 #include <gtk/gtkgl.h>
29 #include "rendering.h"
31 #include "gliv_image.h"
34 #include "zoom_frame.h"
35 #include "scrollbars.h"
36 #include "gl_widget.h"
38 #include "files_list.h"
44 extern options_struct
*options
;
45 extern gliv_image
*current_image
;
46 extern GtkWidget
*gl_widget
;
48 /* The gtk timer that calls redraw(). */
49 static guint idle_id
= 0;
51 static void set_filter(gint filter
)
57 * Only the textures in the first map change their filter,
58 * since in the others maps the image is zoomed out.
60 map
= current_image
->maps
;
62 for (id
= 0; id
< map
->nb_tiles
; id
++) {
63 glBindTexture(GL_TEXTURE_2D
, map
->tex_ids
[id
]);
64 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, filter
);
65 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, filter
);
69 static gboolean
is_filtering_enabled(void)
74 /* Only the first map changes its filter. */
75 map
= current_image
->maps
;
77 glBindTexture(GL_TEXTURE_2D
, map
->tex_ids
[0]);
78 glGetTexParameteriv(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, &filter
);
80 return filter
== GL_LINEAR
;
83 static void call_lists(gboolean smooth
, gint level
)
88 if (rt
->filtering_enabled
!= smooth
) {
89 rt
->filtering_enabled
= smooth
;
90 set_filter(smooth
? GL_LINEAR
: GL_NEAREST
);
93 map
= current_image
->maps
+ level
;
95 for (id
= 0; id
< map
->nb_tiles
; id
++)
96 if (matrix_tile_visible(map
->tiles
+ id
))
97 glCallList(map
->list
+ id
);
100 static void draw_checker(void)
102 static guint tex_id
= 0;
104 gfloat half_w
, half_h
;
105 gboolean matrix_changed
;
107 matrix_changed
= get_matrix_has_changed();
109 if (rt
->alpha_checks_changed
) {
111 gushort alpha1
[3] = {
113 options
->alpha1
.green
,
116 gushort alpha2
[3] = {
118 options
->alpha2
.green
,
123 glGenTextures(1, &tex_id
);
125 for (i
= 0; i
< 3; i
++) {
126 texture
[i
] = texture
[9 + i
] = alpha1
[i
];
127 texture
[3 + i
] = texture
[6 + i
] = alpha2
[i
];
130 glBindTexture(GL_TEXTURE_2D
, tex_id
);
132 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
133 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
135 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
136 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
138 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGB
, 2, 2, 0, GL_RGB
,
139 GL_UNSIGNED_SHORT
, texture
);
141 rt
->alpha_checks_changed
= FALSE
;
143 glBindTexture(GL_TEXTURE_2D
, tex_id
);
145 if (matrix_changed
== FALSE
)
146 /* glMatrixMode(GL_MODELVIEW); */
147 /* Save the matrix only if we will not replace it when redrawing. */
152 half_w
= rt
->wid_size
->width
/ 2.0;
153 half_h
= rt
->wid_size
->height
/ 2.0;
157 glTexCoord2f(0.0, 0.0);
158 glVertex2f(-half_w
, -half_h
);
160 glTexCoord2f(half_w
/ 16.0, 0.0);
161 glVertex2f(half_w
, -half_h
);
163 glTexCoord2f(half_w
/ 16.0, half_h
/ 16.0);
164 glVertex2f(half_w
, half_h
);
166 glTexCoord2f(0.0, half_h
/ 16.0);
167 glVertex2f(-half_w
, half_h
);
171 if (matrix_changed
== FALSE
)
172 /* glMatrixMode(GL_MODELVIEW); */
176 static gint
choose_mipmap_level(void)
178 gfloat zoom
, mipmap_ratio
= MIPMAP_RATIO
;
181 if (options
->mipmap
) {
182 zoom
= get_matrix_zoom();
184 while (mipmap_ratio
> zoom
&& level
< current_image
->nb_maps
) {
185 mipmap_ratio
*= MIPMAP_RATIO
;
190 /* Mipmaps should only be scaled down. */
194 /* Called by the timer when a redraw is needed. */
195 static gboolean
redraw(void)
197 static GdkGLDrawable
*gldrawable
= NULL
;
201 if (gldrawable
== NULL
)
203 gldrawable
= gtk_widget_get_gl_drawable(gl_widget
);
205 gdk_gl_drawable_wait_gdk(gldrawable
);
207 glDisable(GL_DITHER
);
209 if (current_image
!= NULL
&& current_image
->has_alpha
&&
210 options
->alpha_checks
)
214 glClear(GL_COLOR_BUFFER_BIT
);
220 if (current_image
!= NULL
) {
224 mipmap_level
= choose_mipmap_level();
225 if (mipmap_level
== 0)
226 filtering
= is_filtering_needed();
230 call_lists(filtering
, mipmap_level
);
233 gdk_gl_drawable_swap_buffers(gldrawable
);
236 gdk_gl_drawable_wait_gl(gldrawable
);
237 report_opengl_errors();
239 /* To remove the idle func. */
244 /* Called the first time an image is displayed. */
247 prioritize_textures(current_image
, TRUE
);
250 delete_selected_image();
251 fill_ident(current_image
);
253 rt
->filtering_enabled
= is_filtering_enabled();
255 if (options
->fullscreen
== FALSE
)
258 if (options
->maximize
|| options
->scaledown
)
259 matrix_set_max_zoom(-1, -1, TRUE
);
261 refresh(REFRESH_NOW
| REFRESH_STATUS
| APPEND_HISTORY
);
263 /* A bit dumb, but needed on some cards. */
264 refresh(REFRESH_NOW
);
266 g_free(current_image
->ident
);
267 current_image
->ident
= NULL
;
269 update_window_title();
272 void zoom_in(gfloat ratio
)
274 gint pointer_x
, pointer_y
;
277 if (options
->zoom_pointer
) {
278 /* The pointer is the zoom center. */
279 gdk_window_get_pointer(gl_widget
->window
, &pointer_x
, &pointer_y
, NULL
);
280 x
= (gfloat
) pointer_x
;
281 y
= (gfloat
) pointer_y
;
283 /* The zoom center is the midle of the window. */
284 x
= rt
->wid_size
->width
/ 2.0;
285 y
= rt
->wid_size
->height
/ 2.0;
288 matrix_zoom(ratio
, x
, y
);
289 refresh(REFRESH_IMAGE
| REFRESH_STATUS
| APPEND_HISTORY
);
292 static gboolean
refresh_image(void)
295 refresh(REFRESH_IMAGE
);
300 void refresh(gint what
)
302 /* GTK does that automatically but with more overhead. */
303 if (what
& REFRESH_IMAGE
) {
305 idle_id
= gtk_idle_add_priority(GDK_PRIORITY_REDRAW
,
306 (GtkFunction
) redraw
, NULL
);
308 } else if (what
& REFRESH_BURST
) {
309 if (options
->fps
<= 0)
310 refresh(REFRESH_IMAGE
);
312 else if (idle_id
== 0)
313 idle_id
= gtk_timeout_add(1000 / options
->fps
,
314 (GtkFunction
) refresh_image
, NULL
);
316 } else if (what
& REFRESH_NOW
) {
318 g_source_remove(idle_id
);
323 if (what
& REFRESH_STATUS
)
326 if (what
& APPEND_HISTORY
)