The revised patch from Leon for new particle effects.
[blender.git] / source / blender / src / glutil.c
1
2
3 /**
4  * $Id$
5  *
6  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version. The Blender
12  * Foundation also sells licenses for use in proprietary software under
13  * the Blender License.  See http://www.blender.org/BL/ for information
14  * about this.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
26  * All rights reserved.
27  *
28  * The Original Code is: all of this file.
29  *
30  * Contributor(s): none yet.
31  *
32  * ***** END GPL/BL DUAL LICENSE BLOCK *****
33  */
34
35 #include <math.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifdef WIN32
42 #include "BLI_winstuff.h"
43 #endif
44
45 #include "MEM_guardedalloc.h"
46
47 #include "DNA_vec_types.h"
48
49 #include "BIF_gl.h"
50 #include "BIF_glutil.h"
51
52         /* Invert line handling */
53         
54 #define glToggle(mode, onoff)   (((onoff)?glEnable:glDisable)(mode))
55
56 static void set_inverted_drawing(int enable) 
57 {
58         glLogicOp(enable?GL_INVERT:GL_COPY);
59
60         /* Use GL_BLEND_EQUATION_EXT on sgi (if we have it),
61          * apparently GL_COLOR_LOGIC_OP doesn't work on O2?
62          * Is this an sgi bug or our bug?
63          */
64 #if defined(__sgi) && defined(GL_BLEND_EQUATION_EXT)
65         glBlendEquationEXT(enable?GL_LOGIC_OP:GL_FUNC_ADD_EXT);
66         glToggle(GL_BLEND, enable);
67 #else
68         glToggle(GL_COLOR_LOGIC_OP, enable);
69 #endif
70
71         glToggle(GL_DITHER, !enable);
72 }
73
74 void sdrawXORline(int x0, int y0, int x1, int y1)
75 {
76         if(x0==x1 && y0==y1) return;
77
78         set_inverted_drawing(1);
79         
80         glBegin(GL_LINES);
81         glVertex2i(x0, y0);
82         glVertex2i(x1, y1);
83         glEnd();
84         
85         set_inverted_drawing(0);
86 }
87
88 void glutil_draw_front_xor_line(int x0, int y0, int x1, int y1)
89 {
90         glReadBuffer(GL_FRONT);
91         glDrawBuffer(GL_FRONT);
92         sdrawXORline(x0, y0, x1, y1);
93         glFlush();
94         glReadBuffer(GL_BACK);
95         glDrawBuffer(GL_BACK);
96         
97 }
98
99 void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
100 {
101         static short old[4][2][2];
102         static char flags[4]= {0, 0, 0, 0};
103         
104                 /* with builtin memory, max 4 lines */
105
106         set_inverted_drawing(1);
107                 
108         glBegin(GL_LINES);
109         if(nr== -1) { /* flush */
110                 for (nr=0; nr<4; nr++) {
111                         if (flags[nr]) {
112                                 glVertex2sv(old[nr][0]);
113                                 glVertex2sv(old[nr][1]);
114                                 flags[nr]= 0;
115                         }
116                 }
117         } else {
118                 if(nr>=0 && nr<4) {
119                         if(flags[nr]) {
120                                 glVertex2sv(old[nr][0]);
121                                 glVertex2sv(old[nr][1]);
122                         }
123
124                         old[nr][0][0]= x0;
125                         old[nr][0][1]= y0;
126                         old[nr][1][0]= x1;
127                         old[nr][1][1]= y1;
128                         
129                         flags[nr]= 1;
130                 }
131                 
132                 glVertex2i(x0, y0);
133                 glVertex2i(x1, y1);
134         }
135         glEnd();
136         
137         set_inverted_drawing(0);
138 }
139
140 void sdrawXORcirc(short xofs, short yofs, float rad)
141 {
142         set_inverted_drawing(1);
143
144         glPushMatrix();
145         glTranslatef(xofs, yofs, 0.0);
146         glutil_draw_lined_arc(0.0, M_PI*2, rad, 20);
147         glPopMatrix();
148
149         set_inverted_drawing(0);
150 }
151
152 void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments) {
153         int i;
154         
155         glBegin(GL_TRIANGLE_FAN);
156         glVertex2f(0.0, 0.0);
157         for (i=0; i<nsegments; i++) {
158                 float t= (float) i/(nsegments-1);
159                 float cur= start + t*angle;
160                 
161                 glVertex2f(cos(cur)*radius, sin(cur)*radius);
162         }
163         glEnd();
164 }
165
166 void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments) {
167         int i;
168         
169         glBegin(GL_LINE_STRIP);
170         for (i=0; i<nsegments; i++) {
171                 float t= (float) i/(nsegments-1);
172                 float cur= start + t*angle;
173                 
174                 glVertex2f(cos(cur)*radius, sin(cur)*radius);
175         }
176         glEnd();
177 }
178
179 int glaGetOneInteger(int param)
180 {
181         int i;
182         glGetIntegerv(param, &i);
183         return i;
184 }
185
186 float glaGetOneFloat(int param)
187 {
188         float v;
189         glGetFloatv(param, &v);
190         return v;
191 }
192
193 void glaRasterPosSafe2f(float x, float y, float known_good_x, float known_good_y)
194 {
195         GLubyte dummy= 0;
196
197                 /* As long as known good coordinates are correct
198                  * this is guarenteed to generate an ok raster
199                  * position (ignoring potential (real) overflow
200                  * issues).
201                  */
202         glRasterPos2f(known_good_x, known_good_y);
203
204                 /* Now shift the raster position to where we wanted
205                  * it in the first place using the glBitmap trick.
206                  */
207         glBitmap(0, 0, 0, 0, x - known_good_x, y - known_good_y, &dummy);
208 }
209
210 static int get_cached_work_texture(int *w_r, int *h_r)
211 {
212         static int texid= -1;
213         static int tex_w= 256;
214         static int tex_h= 256;
215
216         if (texid==-1) {
217                 GLint ltexid= glaGetOneInteger(GL_TEXTURE_2D);
218                 unsigned char *tbuf;
219
220                 glGenTextures(1, &texid);
221
222                 glBindTexture(GL_TEXTURE_2D, texid);
223
224                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
225                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
226                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
227
228                 tbuf= MEM_callocN(tex_w*tex_h*4, "tbuf");
229                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, tbuf);
230                 MEM_freeN(tbuf);
231
232                 glBindTexture(GL_TEXTURE_2D, ltexid);
233         }
234
235         *w_r= tex_w;
236         *h_r= tex_h;
237         return texid;
238 }
239
240 void glaDrawPixelsTex(float x, float y, int img_w, int img_h, void *rect)
241 {
242         unsigned char *uc_rect= (unsigned char*) rect;
243         float xzoom= glaGetOneFloat(GL_ZOOM_X), yzoom= glaGetOneFloat(GL_ZOOM_Y);
244         int ltexid= glaGetOneInteger(GL_TEXTURE_2D);
245         int lrowlength= glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
246         int subpart_x, subpart_y, tex_w, tex_h;
247         int texid= get_cached_work_texture(&tex_w, &tex_h);
248         int nsubparts_x= (img_w+(tex_w-1))/tex_w;
249         int nsubparts_y= (img_h+(tex_h-1))/tex_h;
250
251         glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w);
252         glBindTexture(GL_TEXTURE_2D, texid);
253
254         for (subpart_y=0; subpart_y<nsubparts_y; subpart_y++) {
255                 for (subpart_x=0; subpart_x<nsubparts_x; subpart_x++) {
256                         int subpart_w= (subpart_x==nsubparts_x-1)?(img_w-subpart_x*tex_w):tex_w;
257                         int subpart_h= (subpart_y==nsubparts_y-1)?(img_h-subpart_y*tex_h):tex_h;
258                         float rast_x= x+subpart_x*tex_w*xzoom;
259                         float rast_y= y+subpart_y*tex_h*yzoom;
260
261                         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, GL_RGBA, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y*tex_w)*img_w*4 + (subpart_x*tex_w)*4]);
262
263                         glColor3ub(255, 255, 255);
264                         glEnable(GL_TEXTURE_2D);
265                         glBegin(GL_QUADS);
266                         glTexCoord2f(0, 0);
267                         glVertex2f(rast_x, rast_y);
268
269                         glTexCoord2f((float) subpart_w/tex_w, 0);
270                         glVertex2f(rast_x+subpart_w*xzoom, rast_y);
271
272                         glTexCoord2f((float) subpart_w/tex_w, (float) subpart_h/tex_h);
273                         glVertex2f(rast_x+subpart_w*xzoom, rast_y+subpart_h*yzoom);
274
275                         glTexCoord2f(0, (float) subpart_h/tex_h);
276                         glVertex2f(rast_x, rast_y+subpart_h*yzoom);
277                         glEnd();
278                         glDisable(GL_TEXTURE_2D);
279                 }
280         }
281
282         glBindTexture(GL_TEXTURE_2D, ltexid);
283         glPixelStorei(GL_UNPACK_ROW_LENGTH, lrowlength);
284 }
285
286 void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, void *rect)
287 {
288         unsigned char *uc_rect= (unsigned char*) rect;
289         float origin_x= 0.375;
290         float origin_y= 0.375;
291
292                 /* Trivial case */
293         if (x>=origin_x && y>=origin_y) {
294                 glRasterPos2f(x, y);
295                 glDrawPixels(img_w, img_h, GL_RGBA, GL_UNSIGNED_BYTE, uc_rect);
296         } else {
297                 int old_row_length= glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
298                 float xzoom= glaGetOneFloat(GL_ZOOM_X);
299                 float yzoom= glaGetOneFloat(GL_ZOOM_Y);
300
301                         /* The pixel space coordinate of the intersection of
302                          * the [zoomed] image with the origin.
303                          */
304                 float ix= (origin_x-x)/xzoom;
305                 float iy= (origin_y-y)/yzoom;
306         
307                         /* The maximum pixel amounts the image can cropped
308                          * without exceeding the origin.
309                          */
310                 int off_x= floor((ix>origin_x)?ix:origin_x);
311                 int off_y= floor((iy>origin_y)?iy:origin_y);
312                 
313                         /* The zoomed space coordinate of the raster
314                          * position.
315                          */
316                 float rast_x= x + off_x*xzoom;
317                 float rast_y= y + off_y*yzoom;
318                 
319                 if (off_x<img_w && off_y<img_h) {
320                         glaRasterPosSafe2f(rast_x, rast_y, origin_x, origin_y);
321                         glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w);
322                         glDrawPixels(img_w-off_x, img_h-off_y, GL_RGBA, GL_UNSIGNED_BYTE, uc_rect+off_y*img_w*4+off_x*4);
323                         glPixelStorei(GL_UNPACK_ROW_LENGTH,  old_row_length);
324                 }
325         }
326 }
327
328 /* 2D Drawing Assistance */
329
330 void glaDefine2DArea(rcti *screen_rect)
331 {
332         int sc_w= screen_rect->xmax - screen_rect->xmin;
333         int sc_h= screen_rect->ymax - screen_rect->ymin;
334
335         glViewport(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
336         glScissor(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
337
338                 /* The 0.375 magic number is to shift the matrix so that
339                  * both raster and vertex integer coordinates fall at pixel
340                  * centers properly. For a longer discussion see the OpenGL
341                  * Programming Guide, Appendix H, Correctness Tips.
342                  */
343
344         glMatrixMode(GL_PROJECTION);
345         glLoadIdentity();
346         glOrtho(0.0, sc_w, 0.0, sc_h, -1, 1);
347         glTranslatef(0.375, 0.375, 0.0);
348
349         glMatrixMode(GL_MODELVIEW);
350         glLoadIdentity();
351 }
352
353 struct gla2DDrawInfo {
354         int orig_vp[4], orig_sc[4];
355         float orig_projmat[16], orig_viewmat[16];
356
357         rcti screen_rect;
358         rctf world_rect;
359
360         float wo_to_sc[2];
361 };
362
363 gla2DDrawInfo *glaBegin2DDraw(rcti *screen_rect, rctf *world_rect) 
364 {
365         gla2DDrawInfo *di= MEM_mallocN(sizeof(*di), "gla2DDrawInfo");
366         int sc_w, sc_h;
367         float wo_w, wo_h;
368
369         glGetIntegerv(GL_VIEWPORT, di->orig_vp);
370         glGetIntegerv(GL_SCISSOR_BOX, di->orig_sc);
371         glGetFloatv(GL_PROJECTION_MATRIX, di->orig_projmat);
372         glGetFloatv(GL_MODELVIEW_MATRIX, di->orig_viewmat);
373
374         di->screen_rect= *screen_rect;
375         if (world_rect) {
376                 di->world_rect= *world_rect;
377         } else {
378                 di->world_rect.xmin= di->screen_rect.xmin;
379                 di->world_rect.ymin= di->screen_rect.ymin;
380                 di->world_rect.xmax= di->screen_rect.xmax;
381                 di->world_rect.ymax= di->screen_rect.ymax;
382         }
383
384         sc_w= (di->screen_rect.xmax-di->screen_rect.xmin);
385         sc_h= (di->screen_rect.ymax-di->screen_rect.ymin);
386         wo_w= (di->world_rect.xmax-di->world_rect.xmin);
387         wo_h= (di->world_rect.ymax-di->world_rect.ymin);
388
389         di->wo_to_sc[0]= sc_w/wo_w;
390         di->wo_to_sc[1]= sc_h/wo_h;
391
392         glaDefine2DArea(&di->screen_rect);
393
394         return di;
395 }
396
397 void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r)
398 {
399         *sc_x_r= (wo_x - di->world_rect.xmin)*di->wo_to_sc[0];
400         *sc_y_r= (wo_y - di->world_rect.ymin)*di->wo_to_sc[1];
401 }
402 void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2])
403 {
404         screen_r[0]= (world[0] - di->world_rect.xmin)*di->wo_to_sc[0];
405         screen_r[1]= (world[1] - di->world_rect.ymin)*di->wo_to_sc[1];
406 }
407
408 void glaEnd2DDraw(gla2DDrawInfo *di)
409 {
410         glViewport(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
411         glScissor(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
412         glMatrixMode(GL_PROJECTION);
413         glLoadMatrixf(di->orig_projmat);
414         glMatrixMode(GL_MODELVIEW);
415         glLoadMatrixf(di->orig_viewmat);
416
417         MEM_freeN(di);
418 }