gliv-1.7
[gliv.git] / src / rendering.c
blobd20b08db7c75f43410977038c7cd63abcd5e4f2c
1 /*
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 <gfc@altern.org>
21 /************************
22 * Rendering functions. *
23 ************************/
25 #include "gliv.h"
27 #include <gtk/gtkgl.h>
28 #include <GL/gl.h>
30 extern rt_struct *rt;
31 extern options_struct *options;
32 extern gliv_image *current_image;
33 extern GtkWidget *gl_widget;
35 static guint idle_id = 0;
37 static void set_filter(gint filter)
39 gint level, id;
40 texture_map *map;
42 /* All textures have the same parameters. */
44 for (level = 0; level < current_image->nb_maps; level++) {
45 map = current_image->maps + level;
47 for (id = 0; id < map->nb_tiles; id++) {
48 glBindTexture(GL_TEXTURE_2D, map->tex_ids[id]);
49 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
50 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
55 static void call_lists(gboolean smooth, gint level)
57 gint id;
58 texture_map *map;
60 if (rt->filtering_enabled != smooth) {
61 rt->filtering_enabled = smooth;
62 set_filter(smooth ? GL_LINEAR : GL_NEAREST);
65 map = current_image->maps + level;
67 for (id = 0; id < map->nb_tiles; id++)
68 if (matrix_tile_visible(map->tiles + id))
69 glCallList(map->list + id);
72 static void draw_checker(void)
74 static guint tex_id = 0;
75 gint i;
76 gfloat half_w, half_h;
77 gboolean matrix_changed;
79 matrix_changed = get_matrix_has_changed();
81 if (rt->alpha_checks_changed) {
82 gushort texture[12];
84 if (tex_id == 0)
85 glGenTextures(1, &tex_id);
87 for (i = 0; i < 3; i++) {
88 texture[i] = texture[9 + i] = options->alpha1[i];
89 texture[3 + i] = texture[6 + i] = options->alpha2[i];
92 glBindTexture(GL_TEXTURE_2D, tex_id);
94 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
95 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
97 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
98 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
100 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB,
101 GL_UNSIGNED_SHORT, texture);
103 rt->alpha_checks_changed = FALSE;
104 } else
105 glBindTexture(GL_TEXTURE_2D, tex_id);
107 if (matrix_changed == FALSE)
108 /* glMatrixMode(GL_MODELVIEW); */
109 /* Save the matrix only if we will not replace it when redrawing. */
110 glPushMatrix();
112 glLoadIdentity();
114 half_w = rt->wid_size->width / 2.0;
115 half_h = rt->wid_size->height / 2.0;
117 glBegin(GL_QUADS);
119 glTexCoord2f(0.0, 0.0);
120 glVertex2f(-half_w, -half_h);
122 glTexCoord2f(half_w / 16.0, 0.0);
123 glVertex2f(half_w, -half_h);
125 glTexCoord2f(half_w / 16.0, half_h / 16.0);
126 glVertex2f(half_w, half_h);
128 glTexCoord2f(0.0, half_h / 16.0);
129 glVertex2f(-half_w, half_h);
131 glEnd();
133 if (matrix_changed == FALSE)
134 /* glMatrixMode(GL_MODELVIEW); */
135 glPopMatrix();
138 static gint choose_mipmap_level(void)
140 gfloat zoom, mipmap_ratio = MIPMAP_RATIO;
141 gint level = 1;
143 if (options->mipmap) {
144 zoom = get_matrix_zoom();
146 while (mipmap_ratio > zoom && level < current_image->nb_maps) {
147 mipmap_ratio *= MIPMAP_RATIO;
148 level++;
152 /* Mipmaps should only be scaled down. */
153 return level - 1;
156 static gboolean redraw(void)
158 GdkGLDrawable *gldrawable;
160 clear_zoom_frame();
162 gldrawable = gtk_widget_get_gl_drawable(gl_widget);
163 gdk_gl_drawable_wait_gdk(gldrawable);
165 glDisable(GL_DITHER);
167 if (current_image != NULL && current_image->has_alpha &&
168 options->alpha_checks)
170 draw_checker();
171 else
172 glClear(GL_COLOR_BUFFER_BIT);
174 glEnable(GL_DITHER);
176 write_gl_matrix();
178 if (current_image != NULL)
179 call_lists(is_filtering_needed(), choose_mipmap_level());
181 gdk_gl_drawable_swap_buffers(gldrawable);
183 if (current_image != NULL && options->scrollbars)
184 update_scrollbars(TRUE);
186 gdk_gl_drawable_wait_gl(gldrawable);
188 /* To remove the idle func. */
189 idle_id = 0;
190 return FALSE;
193 void render(void)
195 prioritize_textures(current_image, TRUE);
197 matrix_reset();
198 delete_selected_image();
199 fill_ident(current_image);
201 rt->filtering_enabled = FALSE;
203 if (options->fullscreen == FALSE)
204 goto_window(FALSE);
206 if (options->maximize || options->scaledown)
207 matrix_set_max_zoom(-1, -1, TRUE);
209 refresh(REFRESH_NOW | REFRESH_STATUS | APPEND_HISTORY);
211 /* A bit dumb, but needed on some cards. */
212 refresh(REFRESH_NOW);
214 g_free(current_image->ident);
215 current_image->ident = NULL;
217 update_window_title();
218 process_events();
221 void zoom_in(gfloat ratio)
223 gint pointer_x, pointer_y;
224 gfloat x, y;
226 if (options->zoom_pointer) {
227 /* The pointer is the zoom center. */
228 gdk_window_get_pointer(gl_widget->window, &pointer_x, &pointer_y, NULL);
229 x = (gfloat) pointer_x;
230 y = (gfloat) pointer_y;
231 } else {
232 /* The zoom center is the midle of the window. */
233 x = rt->wid_size->width / 2.0;
234 y = rt->wid_size->height / 2.0;
237 matrix_zoom(ratio, x, y);
238 refresh(REFRESH_IMAGE | REFRESH_STATUS | APPEND_HISTORY);
241 void refresh(gint what)
243 /* GTK does that automatically but with more overhead. */
244 if (what & REFRESH_IMAGE) {
246 if (idle_id == 0)
247 idle_id = gtk_idle_add_priority(GDK_PRIORITY_REDRAW,
248 (GtkFunction) redraw, NULL);
250 } else if (what & REFRESH_NOW) {
252 if (idle_id != 0)
253 gtk_idle_remove(idle_id);
255 redraw();
258 if (what & REFRESH_STATUS)
259 update_status_bar();
261 if (what & APPEND_HISTORY)
262 append_history();