2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/editors/screen/glutil.c
34 #include "MEM_guardedalloc.h"
36 #include "DNA_userdef_types.h"
37 #include "DNA_vec_types.h"
40 #include "BLI_utildefines.h"
42 #include "BLI_threads.h"
44 #include "BKE_blender.h"
45 #include "BKE_colortools.h"
48 #include "BIF_glutil.h"
50 #ifndef GL_CLAMP_TO_EDGE
51 #define GL_CLAMP_TO_EDGE 0x812F
55 /* ******************************************** */
57 /* defined in BIF_gl.h */
58 const GLubyte stipple_halftone[128] = {
59 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
60 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
61 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
62 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
63 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
64 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
65 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
66 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
67 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
68 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
69 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
70 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
71 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
72 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
73 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
74 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55};
77 /* repeat this pattern
85 const GLubyte stipple_quarttone[128] = {
86 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
87 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
88 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
89 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
90 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
91 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
92 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
93 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0};
96 const GLubyte stipple_diag_stripes_pos[128] = {
97 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
98 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
99 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
100 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
101 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
102 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
103 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
104 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
105 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
106 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
107 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
108 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
109 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
110 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
111 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
112 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f};
115 const GLubyte stipple_diag_stripes_neg[128] = {
116 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
117 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
118 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
119 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
120 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
121 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
122 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
123 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
124 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
125 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
126 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
127 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
128 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
129 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
130 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
131 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80};
134 void fdrawbezier(float vec[4][3])
137 float curve_res = 24, spline_step = 0.0f;
139 dist = 0.5f * ABS(vec[0][0] - vec[3][0]);
141 /* check direction later, for top sockets */
142 vec[1][0] = vec[0][0] + dist;
143 vec[1][1] = vec[0][1];
145 vec[2][0] = vec[3][0] - dist;
146 vec[2][1] = vec[3][1];
147 /* we can reuse the dist variable here to increment the GL curve eval amount*/
148 dist = 1.0f / curve_res;
151 glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
152 glBegin(GL_LINE_STRIP);
153 while (spline_step < 1.000001f) {
156 UI_ThemeColorBlend(th_col1, th_col2, spline_step);
158 glEvalCoord1f(spline_step);
164 void fdrawline(float x1, float y1, float x2, float y2)
168 glBegin(GL_LINE_STRIP);
169 v[0] = x1; v[1] = y1;
171 v[0] = x2; v[1] = y2;
176 void fdrawbox(float x1, float y1, float x2, float y2)
180 glBegin(GL_LINE_STRIP);
182 v[0] = x1; v[1] = y1;
184 v[0] = x1; v[1] = y2;
186 v[0] = x2; v[1] = y2;
188 v[0] = x2; v[1] = y1;
190 v[0] = x1; v[1] = y1;
196 void fdrawcheckerboard(float x1, float y1, float x2, float y2)
198 unsigned char col1[4] = {40, 40, 40}, col2[4] = {50, 50, 50};
200 GLubyte checker_stipple[32 * 32 / 8] = {
201 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
202 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
203 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
204 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
205 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
206 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
207 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
208 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255};
211 glRectf(x1, y1, x2, y2);
214 glEnable(GL_POLYGON_STIPPLE);
215 glPolygonStipple(checker_stipple);
216 glRectf(x1, y1, x2, y2);
217 glDisable(GL_POLYGON_STIPPLE);
220 void sdrawline(short x1, short y1, short x2, short y2)
224 glBegin(GL_LINE_STRIP);
225 v[0] = x1; v[1] = y1;
227 v[0] = x2; v[1] = y2;
240 static void sdrawtripoints(short x1, short y1, short x2, short y2)
243 v[0] = x1; v[1] = y1;
245 v[0] = x1; v[1] = y2;
247 v[0] = x2; v[1] = y1;
251 void sdrawtri(short x1, short y1, short x2, short y2)
253 glBegin(GL_LINE_STRIP);
254 sdrawtripoints(x1, y1, x2, y2);
258 void sdrawtrifill(short x1, short y1, short x2, short y2)
260 glBegin(GL_TRIANGLES);
261 sdrawtripoints(x1, y1, x2, y2);
265 void sdrawbox(short x1, short y1, short x2, short y2)
269 glBegin(GL_LINE_STRIP);
271 v[0] = x1; v[1] = y1;
273 v[0] = x1; v[1] = y2;
275 v[0] = x2; v[1] = y2;
277 v[0] = x2; v[1] = y1;
279 v[0] = x1; v[1] = y1;
286 /* ******************************************** */
288 void setlinestyle(int nr)
291 glDisable(GL_LINE_STIPPLE);
295 glEnable(GL_LINE_STIPPLE);
296 if (U.pixelsize > 1.0f)
297 glLineStipple(nr, 0xCCCC);
299 glLineStipple(nr, 0xAAAA);
303 /* Invert line handling */
305 #define GL_TOGGLE(mode, onoff) (((onoff) ? glEnable : glDisable)(mode))
307 void set_inverted_drawing(int enable)
309 glLogicOp(enable ? GL_INVERT : GL_COPY);
310 GL_TOGGLE(GL_COLOR_LOGIC_OP, enable);
311 GL_TOGGLE(GL_DITHER, !enable);
314 void sdrawXORline(int x0, int y0, int x1, int y1)
316 if (x0 == x1 && y0 == y1) return;
318 set_inverted_drawing(1);
325 set_inverted_drawing(0);
328 void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
330 static short old[4][2][2];
331 static char flags[4] = {0, 0, 0, 0};
333 /* with builtin memory, max 4 lines */
335 set_inverted_drawing(1);
338 if (nr == -1) { /* flush */
339 for (nr = 0; nr < 4; nr++) {
341 glVertex2sv(old[nr][0]);
342 glVertex2sv(old[nr][1]);
348 if (nr >= 0 && nr < 4) {
350 glVertex2sv(old[nr][0]);
351 glVertex2sv(old[nr][1]);
367 set_inverted_drawing(0);
370 void fdrawXORellipse(float xofs, float yofs, float hw, float hh)
374 set_inverted_drawing(1);
377 glTranslatef(xofs, yofs, 0.0f);
378 glScalef(1.0f, hh / hw, 1.0f);
379 glutil_draw_lined_arc(0.0, M_PI * 2.0, hw, 20);
382 set_inverted_drawing(0);
384 void fdrawXORcirc(float xofs, float yofs, float rad)
386 set_inverted_drawing(1);
389 glTranslatef(xofs, yofs, 0.0);
390 glutil_draw_lined_arc(0.0, M_PI * 2.0, rad, 20);
393 set_inverted_drawing(0);
396 void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments)
400 glBegin(GL_TRIANGLE_FAN);
401 glVertex2f(0.0, 0.0);
402 for (i = 0; i < nsegments; i++) {
403 float t = (float) i / (nsegments - 1);
404 float cur = start + t * angle;
406 glVertex2f(cosf(cur) * radius, sinf(cur) * radius);
411 void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments)
415 glBegin(GL_LINE_STRIP);
416 for (i = 0; i < nsegments; i++) {
417 float t = (float) i / (nsegments - 1);
418 float cur = start + t * angle;
420 glVertex2f(cosf(cur) * radius, sinf(cur) * radius);
425 int glaGetOneInteger(int param)
428 glGetIntegerv(param, &i);
432 float glaGetOneFloat(int param)
435 glGetFloatv(param, &v);
439 void glaRasterPosSafe2f(float x, float y, float known_good_x, float known_good_y)
443 /* As long as known good coordinates are correct
444 * this is guaranteed to generate an ok raster
445 * position (ignoring potential (real) overflow
448 glRasterPos2f(known_good_x, known_good_y);
450 /* Now shift the raster position to where we wanted
451 * it in the first place using the glBitmap trick.
453 glBitmap(0, 0, 0, 0, x - known_good_x, y - known_good_y, &dummy);
456 static int get_cached_work_texture(int *w_r, int *h_r)
458 static GLint texid = -1;
459 static int tex_w = 256;
460 static int tex_h = 256;
463 GLint ltexid = glaGetOneInteger(GL_TEXTURE_2D);
466 glGenTextures(1, (GLuint *)&texid);
468 glBindTexture(GL_TEXTURE_2D, texid);
470 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
471 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
473 tbuf = MEM_callocN(tex_w * tex_h * 4, "tbuf");
474 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, tbuf);
477 glBindTexture(GL_TEXTURE_2D, ltexid);
485 void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, void *rect, float scaleX, float scaleY)
487 unsigned char *uc_rect = (unsigned char *) rect;
488 float *f_rect = (float *)rect;
489 float xzoom = glaGetOneFloat(GL_ZOOM_X), yzoom = glaGetOneFloat(GL_ZOOM_Y);
490 int ltexid = glaGetOneInteger(GL_TEXTURE_2D);
491 int lrowlength = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
492 int subpart_x, subpart_y, tex_w, tex_h;
493 int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
494 int texid = get_cached_work_texture(&tex_w, &tex_h);
496 /* Specify the color outside this function, and tex will modulate it.
497 * This is useful for changing alpha without using glPixelTransferf()
499 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
500 glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w);
501 glBindTexture(GL_TEXTURE_2D, texid);
503 /* don't want nasty border artifacts */
504 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
505 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
508 /* workaround for os x 10.5/10.6 driver bug: http://lists.apple.com/archives/Mac-opengl/2008/Jul/msg00117.html */
509 glPixelZoom(1.f, 1.f);
512 /* setup seamless 2=on, 0=off */
513 seamless = ((tex_w < img_w || tex_h < img_h) && tex_w > 2 && tex_h > 2) ? 2 : 0;
515 offset_x = tex_w - seamless;
516 offset_y = tex_h - seamless;
518 nsubparts_x = (img_w + (offset_x - 1)) / (offset_x);
519 nsubparts_y = (img_h + (offset_y - 1)) / (offset_y);
521 for (subpart_y = 0; subpart_y < nsubparts_y; subpart_y++) {
522 for (subpart_x = 0; subpart_x < nsubparts_x; subpart_x++) {
523 int remainder_x = img_w - subpart_x * offset_x;
524 int remainder_y = img_h - subpart_y * offset_y;
525 int subpart_w = (remainder_x < tex_w) ? remainder_x : tex_w;
526 int subpart_h = (remainder_y < tex_h) ? remainder_y : tex_h;
527 int offset_left = (seamless && subpart_x != 0) ? 1 : 0;
528 int offset_bot = (seamless && subpart_y != 0) ? 1 : 0;
529 int offset_right = (seamless && remainder_x > tex_w) ? 1 : 0;
530 int offset_top = (seamless && remainder_y > tex_h) ? 1 : 0;
531 float rast_x = x + subpart_x * offset_x * xzoom;
532 float rast_y = y + subpart_y * offset_y * yzoom;
534 /* check if we already got these because we always get 2 more when doing seamless*/
535 if (subpart_w <= seamless || subpart_h <= seamless)
538 if (format == GL_FLOAT) {
539 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, GL_RGBA, GL_FLOAT, &f_rect[subpart_y * offset_y * img_w * 4 + subpart_x * offset_x * 4]);
541 /* add an extra border of pixels so linear looks ok at edges of full image. */
542 if (subpart_w < tex_w)
543 glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, GL_RGBA, GL_FLOAT, &f_rect[subpart_y * offset_y * img_w * 4 + (subpart_x * offset_x + subpart_w - 1) * 4]);
544 if (subpart_h < tex_h)
545 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, GL_RGBA, GL_FLOAT, &f_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * 4 + subpart_x * offset_x * 4]);
546 if (subpart_w < tex_w && subpart_h < tex_h)
547 glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, GL_RGBA, GL_FLOAT, &f_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * 4 + (subpart_x * offset_x + subpart_w - 1) * 4]);
550 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, GL_RGBA, GL_UNSIGNED_BYTE, &uc_rect[subpart_y * offset_y * img_w * 4 + subpart_x * offset_x * 4]);
552 if (subpart_w < tex_w)
553 glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, GL_RGBA, GL_UNSIGNED_BYTE, &uc_rect[subpart_y * offset_y * img_w * 4 + (subpart_x * offset_x + subpart_w - 1) * 4]);
554 if (subpart_h < tex_h)
555 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, GL_RGBA, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * 4 + subpart_x * offset_x * 4]);
556 if (subpart_w < tex_w && subpart_h < tex_h)
557 glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * 4 + (subpart_x * offset_x + subpart_w - 1) * 4]);
560 glEnable(GL_TEXTURE_2D);
562 glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(0 + offset_bot) / tex_h);
563 glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * yzoom);
565 glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(0 + offset_bot) / tex_h);
566 glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)offset_bot * yzoom);
568 glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(subpart_h - offset_top) / tex_h);
569 glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);
571 glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(subpart_h - offset_top) / tex_h);
572 glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);
574 glDisable(GL_TEXTURE_2D);
578 glBindTexture(GL_TEXTURE_2D, ltexid);
579 glPixelStorei(GL_UNPACK_ROW_LENGTH, lrowlength);
580 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
583 /* workaround for os x 10.5/10.6 driver bug (above) */
584 glPixelZoom(xzoom, yzoom);
588 void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, void *rect)
590 glaDrawPixelsTexScaled(x, y, img_w, img_h, format, rect, 1.0f, 1.0f);
593 void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect)
595 float xzoom = glaGetOneFloat(GL_ZOOM_X);
596 float yzoom = glaGetOneFloat(GL_ZOOM_Y);
598 /* The pixel space coordinate of the intersection of
599 * the [zoomed] image with the origin.
601 float ix = -x / xzoom;
602 float iy = -y / yzoom;
604 /* The maximum pixel amounts the image can be cropped
605 * at the lower left without exceeding the origin.
607 int off_x = floor(max_ff(ix, 0.0f));
608 int off_y = floor(max_ff(iy, 0.0f));
610 /* The zoomed space coordinate of the raster position
611 * (starting at the lower left most unclipped pixel).
613 float rast_x = x + off_x * xzoom;
614 float rast_y = y + off_y * yzoom;
619 /* Determine the smallest number of pixels we need to draw
620 * before the image would go off the upper right corner.
622 * It may seem this is just an optimization but some graphics
623 * cards (ATI) freak out if there is a large zoom factor and
624 * a large number of pixels off the screen (probably at some
625 * level the number of image pixels to draw is getting multiplied
626 * by the zoom and then clamped). Making sure we draw the
627 * fewest pixels possible keeps everyone mostly happy (still
628 * fails if we zoom in on one really huge pixel so that it
629 * covers the entire screen).
631 glGetFloatv(GL_SCISSOR_BOX, scissor);
632 draw_w = min_ii(img_w - off_x, ceil((scissor[2] - rast_x) / xzoom));
633 draw_h = min_ii(img_h - off_y, ceil((scissor[3] - rast_y) / yzoom));
635 if (draw_w > 0 && draw_h > 0) {
636 int old_row_length = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
638 /* Don't use safe RasterPos (slower) if we can avoid it. */
639 if (rast_x >= 0 && rast_y >= 0) {
640 glRasterPos2f(rast_x, rast_y);
643 glaRasterPosSafe2f(rast_x, rast_y, 0, 0);
646 glPixelStorei(GL_UNPACK_ROW_LENGTH, row_w);
647 if (format == GL_LUMINANCE || format == GL_RED) {
648 if (type == GL_FLOAT) {
649 float *f_rect = (float *)rect;
650 glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y * row_w + off_x));
652 else if (type == GL_INT || type == GL_UNSIGNED_INT) {
653 int *i_rect = (int *)rect;
654 glDrawPixels(draw_w, draw_h, format, type, i_rect + (off_y * row_w + off_x));
658 if (type == GL_FLOAT) {
659 float *f_rect = (float *)rect;
660 glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y * row_w + off_x) * 4);
662 else if (type == GL_UNSIGNED_BYTE) {
663 unsigned char *uc_rect = (unsigned char *) rect;
664 glDrawPixels(draw_w, draw_h, format, type, uc_rect + (off_y * row_w + off_x) * 4);
668 glPixelStorei(GL_UNPACK_ROW_LENGTH, old_row_length);
672 /* uses either DrawPixelsSafe or DrawPixelsTex, based on user defined maximum */
673 void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, void *rect)
675 if (U.image_gpubuffer_limit) {
676 /* Megapixels, use float math to prevent overflow */
677 float img_size = ((float)img_w * (float)img_h) / (1024.0f * 1024.0f);
679 if (U.image_gpubuffer_limit > (int)img_size) {
680 glColor4f(1.0, 1.0, 1.0, 1.0);
681 glaDrawPixelsTex(x, y, img_w, img_h, format, rect);
685 glaDrawPixelsSafe(x, y, img_w, img_h, img_w, GL_RGBA, format, rect);
688 /* 2D Drawing Assistance */
690 void glaDefine2DArea(rcti *screen_rect)
692 const int sc_w = BLI_rcti_size_x(screen_rect) + 1;
693 const int sc_h = BLI_rcti_size_y(screen_rect) + 1;
695 glViewport(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
696 glScissor(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
698 /* The GLA_PIXEL_OFS magic number is to shift the matrix so that
699 * both raster and vertex integer coordinates fall at pixel
700 * centers properly. For a longer discussion see the OpenGL
701 * Programming Guide, Appendix H, Correctness Tips.
704 glMatrixMode(GL_PROJECTION);
706 glOrtho(0.0, sc_w, 0.0, sc_h, -1, 1);
707 glTranslatef(GLA_PIXEL_OFS, GLA_PIXEL_OFS, 0.0);
709 glMatrixMode(GL_MODELVIEW);
715 struct gla2DDrawInfo {
716 int orig_vp[4], orig_sc[4];
717 float orig_projmat[16], orig_viewmat[16];
725 void gla2DGetMap(gla2DDrawInfo *di, rctf *rect)
727 *rect = di->world_rect;
730 void gla2DSetMap(gla2DDrawInfo *di, rctf *rect)
735 di->world_rect = *rect;
737 sc_w = BLI_rcti_size_x(&di->screen_rect);
738 sc_h = BLI_rcti_size_y(&di->screen_rect);
739 wo_w = BLI_rcti_size_x(&di->world_rect);
740 wo_h = BLI_rcti_size_y(&di->world_rect);
742 di->wo_to_sc[0] = sc_w / wo_w;
743 di->wo_to_sc[1] = sc_h / wo_h;
746 gla2DDrawInfo *glaBegin2DDraw(rcti *screen_rect, rctf *world_rect)
748 gla2DDrawInfo *di = MEM_mallocN(sizeof(*di), "gla2DDrawInfo");
752 glGetIntegerv(GL_VIEWPORT, (GLint *)di->orig_vp);
753 glGetIntegerv(GL_SCISSOR_BOX, (GLint *)di->orig_sc);
754 glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *)di->orig_projmat);
755 glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)di->orig_viewmat);
757 di->screen_rect = *screen_rect;
759 di->world_rect = *world_rect;
762 di->world_rect.xmin = di->screen_rect.xmin;
763 di->world_rect.ymin = di->screen_rect.ymin;
764 di->world_rect.xmax = di->screen_rect.xmax;
765 di->world_rect.ymax = di->screen_rect.ymax;
768 sc_w = BLI_rcti_size_x(&di->screen_rect);
769 sc_h = BLI_rcti_size_y(&di->screen_rect);
770 wo_w = BLI_rcti_size_x(&di->world_rect);
771 wo_h = BLI_rcti_size_y(&di->world_rect);
773 di->wo_to_sc[0] = sc_w / wo_w;
774 di->wo_to_sc[1] = sc_h / wo_h;
776 glaDefine2DArea(&di->screen_rect);
781 void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r)
783 *sc_x_r = (wo_x - di->world_rect.xmin) * di->wo_to_sc[0];
784 *sc_y_r = (wo_y - di->world_rect.ymin) * di->wo_to_sc[1];
786 void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2])
788 screen_r[0] = (world[0] - di->world_rect.xmin) * di->wo_to_sc[0];
789 screen_r[1] = (world[1] - di->world_rect.ymin) * di->wo_to_sc[1];
792 void glaEnd2DDraw(gla2DDrawInfo *di)
794 glViewport(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
795 glScissor(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
796 glMatrixMode(GL_PROJECTION);
797 glLoadMatrixf(di->orig_projmat);
798 glMatrixMode(GL_MODELVIEW);
799 glLoadMatrixf(di->orig_viewmat);
805 /* **************** GL_POINT hack ************************ */
807 static int curmode = 0;
808 static int pointhack = 0;
809 static GLubyte Squaredot[16] = {0xff, 0xff, 0xff, 0xff,
810 0xff, 0xff, 0xff, 0xff,
811 0xff, 0xff, 0xff, 0xff,
812 0xff, 0xff, 0xff, 0xff};
814 void bglBegin(int mode)
818 if (mode == GL_POINTS) {
820 glGetFloatv(GL_POINT_SIZE_RANGE, value);
821 if (value[1] < 2.0f) {
822 glGetFloatv(GL_POINT_SIZE, value);
823 pointhack = floor(value[0] + 0.5f);
824 if (pointhack > 4) pointhack = 4;
833 int bglPointHack(void)
837 glGetFloatv(GL_POINT_SIZE_RANGE, value);
838 if (value[1] < 2.0f) {
839 glGetFloatv(GL_POINT_SIZE, value);
840 pointhack_px = floorf(value[0] + 0.5f);
841 if (pointhack_px > 4) pointhack_px = 4;
848 void bglVertex3fv(const float vec[3])
854 glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot);
863 void bglVertex3f(float x, float y, float z)
868 glRasterPos3f(x, y, z);
869 glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot);
878 void bglVertex2fv(const float vec[2])
884 glBitmap(pointhack, pointhack, (float)pointhack / 2, pointhack / 2, 0.0, 0.0, Squaredot);
896 if (pointhack) pointhack = 0;
901 /* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */
902 void bgl_get_mats(bglMats *mats)
904 const double badvalue = 1.0e-6;
906 glGetDoublev(GL_MODELVIEW_MATRIX, mats->modelview);
907 glGetDoublev(GL_PROJECTION_MATRIX, mats->projection);
908 glGetIntegerv(GL_VIEWPORT, (GLint *)mats->viewport);
910 /* Very strange code here - it seems that certain bad values in the
911 * modelview matrix can cause gluUnProject to give bad results. */
912 if (mats->modelview[0] < badvalue &&
913 mats->modelview[0] > -badvalue)
915 mats->modelview[0] = 0;
917 if (mats->modelview[5] < badvalue &&
918 mats->modelview[5] > -badvalue)
920 mats->modelview[5] = 0;
923 /* Set up viewport so that gluUnProject will give correct values */
924 mats->viewport[0] = 0;
925 mats->viewport[1] = 0;
928 /* *************** glPolygonOffset hack ************* */
930 /* dist is only for ortho now... */
931 void bglPolygonOffset(float viewdist, float dist)
933 static float winmat[16], offset = 0.0;
938 // glEnable(GL_POLYGON_OFFSET_FILL);
939 // glPolygonOffset(-1.0, -1.0);
941 /* hack below is to mimic polygon offset */
942 glMatrixMode(GL_PROJECTION);
943 glGetFloatv(GL_PROJECTION_MATRIX, (float *)winmat);
945 /* dist is from camera to center point */
947 if (winmat[15] > 0.5f) offs = 0.00001f * dist * viewdist; // ortho tweaking
948 else offs = 0.0005f * dist; // should be clipping value or so...
953 glLoadMatrixf(winmat);
954 glMatrixMode(GL_MODELVIEW);
958 glMatrixMode(GL_PROJECTION);
959 winmat[14] += offset;
961 glLoadMatrixf(winmat);
962 glMatrixMode(GL_MODELVIEW);
971 // if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_OFFICIAL))
972 // XXX myswapbuffers(); //hack to get mac intel graphics to show frontbuffer