1 // This is core/vgui/vgui_utils.cxx
2 #include <cstdlib>
3 #include <iostream>
4 #include "vgui_utils.h"
5 //:
6 // \file
7 // \author fsm
8 // \date Oct 99
9 // \brief See vgui_utils.h for a description of this file.
10
11 #ifdef _MSC_VER
12 # include "vcl_msvc_warnings.h"
13 #endif
14 #include <cassert>
15
16 #include "vil1/vil1_rgba.h"
17 #include "vil1/vil1_save.h"
18
19 #include "vgui/vgui_gl.h"
20 #include "vgui/vgui_glu.h"
21 #include "vgui/vgui_utils.h"
22
23 #include "vil/vil_rgba.h"
24 #include "vil/vil_resample_nearest.h"
25 #include "vil/vil_resample_bilin.h"
26
27 //------------------------------------------------------------------------------
28 // copy the buffer into a memory image
29 vil1_memory_image_of<vil1_rgb<GLubyte>>
get_image(double scale)30 vgui_utils::get_image(double scale)
31 {
32 get_gl_scale_default(scale);
33
34 // We should grab the pixels off the front buffer, since that is what is visible.
35 GLint cur_read_buffer;
36 glGetIntegerv(GL_READ_BUFFER, &cur_read_buffer);
37 glReadBuffer(GL_FRONT);
38
39 // get viewport size
40 GLint vp[4]; // x,y,w,h
41 // Needs to be physical for ReadPixels
42 glGetIntegerv(GL_VIEWPORT, vp);
43 unsigned x = vp[0];
44 unsigned y = vp[1];
45 unsigned w = vp[2];
46 unsigned h = vp[3];
47
48 // It's easier to get the buffer in vil1_rgba format and then convert to
49 // RGB, because that avoids alignment problems with glReadPixels.
50 vil1_rgba<GLubyte> * pixels = new vil1_rgba<GLubyte>[w * h];
51
52 // glReadPixels is not affected by Zoom
53 // glPixelZoom(1, 1);
54 glPixelTransferi(GL_MAP_COLOR, 0);
55 glPixelTransferi(GL_RED_SCALE, 1);
56 glPixelTransferi(GL_RED_BIAS, 0);
57 glPixelTransferi(GL_GREEN_SCALE, 1);
58 glPixelTransferi(GL_GREEN_BIAS, 0);
59 glPixelTransferi(GL_BLUE_SCALE, 1);
60 glPixelTransferi(GL_BLUE_BIAS, 0);
61
62 //
63 glPixelStorei(GL_PACK_ALIGNMENT, 1); // byte alignment.
64 glPixelStorei(GL_PACK_ROW_LENGTH, 0); // use default value (the arg to pixel routine).
65 glPixelStorei(GL_PACK_SKIP_PIXELS, 0); //
66 glPixelStorei(GL_PACK_SKIP_ROWS, 0); //
67
68 //
69 glReadPixels(x,
70 y, //
71 w,
72 h, //
73 GL_RGBA, // format
74 GL_UNSIGNED_BYTE, // type
75 pixels);
76
77 glReadBuffer(cur_read_buffer);
78
79 // glReadPixels() reads the pixels from the bottom of the viewport up.
80 // Copy them into a vil1_memory_image_of in the other order :
81 vil1_memory_image_of<vil1_rgb<GLubyte>> colour_buffer(w, h);
82 for (unsigned yy = 0; yy < h; ++yy)
83 for (unsigned xx = 0; xx < w; ++xx)
84 {
85 colour_buffer(xx, h - 1 - yy).r = pixels[xx + w * yy].r;
86 colour_buffer(xx, h - 1 - yy).g = pixels[xx + w * yy].g;
87 colour_buffer(xx, h - 1 - yy).b = pixels[xx + w * yy].b;
88 }
89
90 //
91 delete[] pixels;
92
93 if (scale == 1)
94 return colour_buffer;
95
96 int width_logical = w / scale;
97 int height_logical = h / scale;
98 vil1_memory_image_of<vil1_rgb<GLubyte>> logical_image(width_logical, height_logical);
99
100 // Convert to views for vil_resample_bilin
101 vil_image_view<GLubyte> logical_view(
102 (GLubyte *)logical_image.begin(), width_logical, height_logical, 3, 3, 3 * width_logical, 1);
103 vil_image_view<GLubyte> physical_view((GLubyte *)colour_buffer.begin(), w, h, 3, 3, 3 * w, 1);
104
105 // Resample
106 vil_resample_bilin<GLubyte, GLubyte>(physical_view, logical_view, width_logical, height_logical);
107
108 // Return
109 return logical_image;
110 }
111
112 // return a memory image corresponding to the GL buffer
113 vil1_memory_image_of<vil1_rgb<unsigned char>>
colour_buffer_to_image()114 vgui_utils::colour_buffer_to_image()
115 {
116 vil1_memory_image_of<vil1_rgb<GLubyte>> colour_buffer = vgui_utils::get_image();
117 vil1_memory_image_of<vil1_rgb<unsigned char>> temp(colour_buffer);
118 return temp;
119 }
120
121 // write the GL buffer to a file
122 void
dump_colour_buffer(char const * file)123 vgui_utils::dump_colour_buffer(char const * file)
124 {
125 vil1_memory_image_of<vil1_rgb<GLubyte>> colour_buffer = vgui_utils::get_image();
126 vil1_save(colour_buffer, file);
127 }
128
129 //------------------------------------------------------------------------------
130 // copy the buffer into a vil image view
131 vil_image_view<GLubyte>
get_view(double scale)132 vgui_utils::get_view(double scale)
133 {
134 get_gl_scale_default(scale);
135
136 // get viewport size
137 GLint vp[4]; // x,y,w,h
138 // Needs to be physical for ReadPixels
139 glGetIntegerv(GL_VIEWPORT, vp);
140 unsigned x = vp[0];
141 unsigned y = vp[1];
142 unsigned w = vp[2];
143 unsigned h = vp[3];
144
145 // It's easier to get the buffer in vil_rgba format and then convert to
146 // RGB, because that avoids alignment problems with glReadPixels.
147 vil_rgba<GLubyte> * pixels = new vil_rgba<GLubyte>[w * h];
148
149 // glReadPixels is not affected by Zoom
150 // glPixelZoom(1, 1);
151 glPixelTransferi(GL_MAP_COLOR, 0);
152 glPixelTransferi(GL_RED_SCALE, 1);
153 glPixelTransferi(GL_RED_BIAS, 0);
154 glPixelTransferi(GL_GREEN_SCALE, 1);
155 glPixelTransferi(GL_GREEN_BIAS, 0);
156 glPixelTransferi(GL_BLUE_SCALE, 1);
157 glPixelTransferi(GL_BLUE_BIAS, 0);
158
159 //
160 glPixelStorei(GL_PACK_ALIGNMENT, 1); // byte alignment.
161 glPixelStorei(GL_PACK_ROW_LENGTH, 0); // use default value (the arg to pixel routine).
162 glPixelStorei(GL_PACK_SKIP_PIXELS, 0); //
163 glPixelStorei(GL_PACK_SKIP_ROWS, 0); //
164
165 //
166 glReadPixels(x,
167 y, //
168 w,
169 h, //
170 GL_RGBA, // format
171 GL_UNSIGNED_BYTE, // type
172 pixels);
173
174 // glReadPixels() reads the pixels from the bottom of the viewport up.
175 // Copy them into a vil_image_view in the other order :
176 vil_image_view<GLubyte> view(w, h, 1, 3);
177 for (unsigned yy = 0; yy < h; ++yy)
178 for (unsigned xx = 0; xx < w; ++xx)
179 {
180 view(xx, h - 1 - yy, 0) = pixels[xx + w * yy].r;
181 view(xx, h - 1 - yy, 1) = pixels[xx + w * yy].g;
182 view(xx, h - 1 - yy, 2) = pixels[xx + w * yy].b;
183 }
184
185 //
186 delete[] pixels;
187
188 if (scale == 1)
189 return view;
190
191 int width_logical = w / scale;
192 int height_logical = h / scale;
193 vil_image_view<GLubyte> logical_view(width_logical, height_logical, 1, 3);
194
195 // Don't use bicub here, it's ugly and fully of tons of artifacts. Bilin is ok
196 vil_resample_bilin<GLubyte, GLubyte>(view, logical_view, width_logical, height_logical);
197 return logical_view;
198 }
199
200
201 //: Get an image view corresponding to the OpenGL area
202 vil_image_view<vxl_byte>
colour_buffer_to_view()203 vgui_utils::colour_buffer_to_view()
204 {
205 vil_image_view<GLubyte> buffer = vgui_utils::get_view();
206 vil_image_view<vxl_byte> temp(buffer);
207 return temp;
208 }
209
210
211 //------------------------------------------------------------------------------
212
213 // Copies the contents of the current read colour buffer into the current draw
214 // colour buffer.
215 void
do_copy(double scale)216 vgui_utils::do_copy(double scale)
217 {
218 // void glCopyPixels( GLint x, GLint y, GLsizei width, GLsizei height, GLenum type )
219
220 GLint vp[4]; // x,y,w,h
221
222 get_gl_scale_default(scale);
223
224 // This has to be done in physical pixels
225 glGetIntegerv(GL_VIEWPORT, vp);
226
227 // save matrices and set new :
228 glMatrixMode(GL_MODELVIEW);
229 glPushMatrix();
230 glLoadIdentity();
231
232 glMatrixMode(GL_PROJECTION);
233 glPushMatrix();
234 glLoadIdentity();
235
236 // Transformations are always in logical pixels...
237 // This doesn't matter, as long as the origin is 0,0? The only point of this
238 // is to get the RasterPos at 0,0, so the width and height don't actually
239 // matter.
240 glOrtho(0, vp[2] / scale, 0, vp[3] / scale, -1, +1); // near, far
241
242 // set raster position to the bottom left-hand corner.
243 glRasterPos2i(0, 0);
244
245 // restore old matrices.
246 glMatrixMode(GL_MODELVIEW);
247 glPopMatrix();
248
249 glMatrixMode(GL_PROJECTION);
250 glPopMatrix();
251
252 // copy pixels :
253 glPixelZoom(1, 1); // CopyPixels needs to be physical pixels
254 glPixelTransferi(GL_MAP_COLOR, 0);
255 glPixelTransferi(GL_RED_SCALE, 1);
256 glPixelTransferi(GL_RED_BIAS, 0);
257 glPixelTransferi(GL_GREEN_SCALE, 1);
258 glPixelTransferi(GL_GREEN_BIAS, 0);
259 glPixelTransferi(GL_BLUE_SCALE, 1);
260 glPixelTransferi(GL_BLUE_BIAS, 0);
261 glPixelTransferi(GL_ALPHA_SCALE, 1);
262 glPixelTransferi(GL_ALPHA_BIAS, 0);
263 glDisable(GL_DITHER);
264 glCopyPixels(0,
265 0, // window coordinates of lower left corner
266 vp[2],
267 vp[3], // width and height of region to be copied in physical pixels
268 GL_COLOR); // copy colour values.
269 }
270
271 void
copy_front_to_back()272 vgui_utils::copy_front_to_back()
273 {
274 GLint old_read, old_draw;
275 glGetIntegerv(GL_READ_BUFFER, &old_read);
276 glGetIntegerv(GL_DRAW_BUFFER, &old_draw);
277
278 glReadBuffer(GL_FRONT);
279 glDrawBuffer(GL_BACK);
280 vgui_utils::do_copy();
281
282 glReadBuffer(GLenum(old_read));
283 glDrawBuffer(GLenum(old_draw));
284 }
285
286 void
copy_back_to_front()287 vgui_utils::copy_back_to_front()
288 {
289 GLint old_read, old_draw;
290 glGetIntegerv(GL_READ_BUFFER, &old_read);
291 glGetIntegerv(GL_DRAW_BUFFER, &old_draw);
292
293 glReadBuffer(GL_BACK);
294 glDrawBuffer(GL_FRONT);
295 vgui_utils::do_copy();
296
297 glReadBuffer(GLenum(old_read));
298 glDrawBuffer(GLenum(old_draw));
299 }
300
301 //------------------------------------------------------------------------------
302
303 static GLint gl_old_buffer = -1;
304
305 void
begin_sw_overlay()306 vgui_utils::begin_sw_overlay()
307 {
308 glGetIntegerv(GL_DRAW_BUFFER, &gl_old_buffer);
309 if (gl_old_buffer != GL_NONE)
310 glDrawBuffer(GL_FRONT);
311 }
312
313 void
end_sw_overlay()314 vgui_utils::end_sw_overlay()
315 {
316 if (gl_old_buffer == -1)
317 {
318 std::cerr << "WARNING : end_sw_overlay called before begin_sw_overlay\n";
319 return;
320 }
321
322 glFlush();
323 // revert to rendering into the back buffer :
324 glDrawBuffer((GLenum)gl_old_buffer);
325
326 gl_old_buffer = -1;
327 }
328
329
330 static bool in_pick_mode = false;
331
332 GLuint *
enter_pick_mode(float x,float y,float w,float h)333 vgui_utils::enter_pick_mode(float x, float y, float w, float h)
334 {
335 assert(!in_pick_mode);
336 in_pick_mode = true;
337
338 if (h == 0)
339 h = w;
340
341 static unsigned const HIT_BUFFER_SIZE = 4096;
342 static GLuint buffer[HIT_BUFFER_SIZE];
343
344 // define hit buffer
345 glSelectBuffer(HIT_BUFFER_SIZE, buffer);
346
347 // get viewport
348 GLint viewport[4];
349 vgui_utils::get_glViewport(viewport);
350
351 // enter selection mode
352 glRenderMode(GL_SELECT);
353
354 //
355 glInitNames();
356
357 // save old projection matrix and define viewing volume for selection :
358 glMatrixMode(GL_PROJECTION);
359 glPushMatrix();
360
361 float P[16]; // get current projection matrix
362 glGetFloatv(GL_PROJECTION_MATRIX, P);
363
364 glLoadIdentity(); // make a pick matrix
365 gluPickMatrix(x, y, w, h, viewport); // thank heavens for viewport coordinates.
366
367 glMultMatrixf(P); // right multiply the old matrix onto it
368
369 return buffer;
370 }
371
372 // return number of hits.
373 unsigned
leave_pick_mode()374 vgui_utils::leave_pick_mode()
375 {
376 assert(in_pick_mode);
377 in_pick_mode = false;
378
379 // restore viewing volume and render mode
380 glMatrixMode(GL_PROJECTION);
381 glPopMatrix();
382 return glRenderMode(GL_RENDER);
383 }
384
385 void
process_hits(int num_hits,GLuint * ptr,std::vector<std::vector<unsigned>> & hits)386 vgui_utils::process_hits(int num_hits, GLuint * ptr, std::vector<std::vector<unsigned>> & hits)
387 {
388 #ifdef DEBUG
389 std::cerr << "hits = " << num_hits << std::endl;
390 #endif
391 // for each hit
392 for (int i = 0; i < num_hits; i++)
393 {
394 GLuint num_names = *ptr;
395 #ifdef DEBUG
396 std::cerr << "number of names for hit[" << i << "] = " << num_names << std::endl;
397 #endif
398 ptr++;
399 #ifdef DEBUG
400 std::cerr << " z1 is " << *ptr;
401 #endif
402 ptr++;
403 #ifdef DEBUG
404 std::cerr << "; z2 is " << *ptr << std::endl;
405 #endif
406 ptr++;
407
408 std::vector<unsigned> names;
409 #ifdef DEBUG
410 std::cerr << " the name is ";
411 #endif
412 // for each name
413 for (unsigned int j = 0; j < num_names; j++)
414 {
415 names.push_back(*ptr);
416 #ifdef DEBUG
417 std::cerr << *ptr << ' ';
418 #endif
419 ptr++;
420 }
421 #ifdef DEBUG
422 std::cerr << std::endl << "names.size() " << names.size() << std::endl;
423 #endif
424 hits.push_back(names);
425
426 #ifdef DEBUG
427 std::cerr << std::endl;
428 #endif
429 }
430 #ifdef DEBUG
431 std::cerr << "hits.size() " << hits.size() << std::endl;
432 #endif
433 }
434
435
436 int
bits_per_pixel(GLenum format,GLenum type)437 vgui_utils::bits_per_pixel(GLenum format, GLenum type)
438 {
439 #define M(f, t, size) \
440 if (format == f && type == t) \
441 return size;
442 M(GL_RGB, GL_UNSIGNED_BYTE, 24);
443 M(GL_BGR, GL_UNSIGNED_BYTE, 24);
444 M(GL_RGBA, GL_UNSIGNED_BYTE, 32);
445 #if defined(GL_UNSIGNED_SHORT_5_6_5)
446 M(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16);
447 #endif
448 #if defined(GL_UNSIGNED_SHORT_5_5_5_1)
449 M(GL_RGB, GL_UNSIGNED_SHORT_5_5_5_1, 16);
450 #endif
451 #if defined(GL_BGRA)
452 M(GL_BGRA, GL_UNSIGNED_BYTE, 32);
453 #endif
454 #if defined(GL_EXT_abgr) || defined(GL_ABGR_EXT)
455 M(GL_ABGR_EXT, GL_UNSIGNED_BYTE, 32);
456 #endif
457 #undef M
458
459 std::cerr << "vgui_utils::bits_per_pixel: UNKNOWN COMBO, format = " << format << ", type = " << type << std::endl;
460 std::abort();
461 return 0;
462 }
463
464 /**
465 * Sets the viewport and corrects for physical to logical scaling, so that the
466 * values are always in units of logical pixels, cross platform.
467 *
468 * @param x GLint left in logical pixels
469 * @param y GLint bottom in logical pixels
470 * @param width GLint width in logical pixels
471 * @param height GLint height in logical pixels
472 * @param scale The scale factor used. Defaults to 0, meaning auto determine
473 * using vgui_adaptor::current. If this is not correct, the scale
474 * factor can manually be set
475 */
476 void
set_glViewport(GLint x,GLint y,GLsizei width,GLsizei height,double scale)477 vgui_utils::set_glViewport(GLint x, GLint y, GLsizei width, GLsizei height, double scale)
478 {
479 get_gl_scale_default(scale);
480
481 glViewport(x * scale, y * scale, width * scale, height * scale);
482 }
483
484 /**
485 * Sets the scissors box and corrects for physical to logical scaling, so that
486 * the values are always in units of logical pixels, cross platform.
487 *
488 * @param x GLint left in logical pixels
489 * @param y GLint bottom in logical pixels
490 * @param width GLint width in logical pixels
491 * @param height GLint height in logical pixels
492 * @param scale The scale factor used. Defaults to 0, meaning auto determine
493 * using vgui_adaptor::current. If this is not correct, the scale
494 * factor can manually be set
495 */
496 void
set_glScissor(GLint x,GLint y,GLsizei width,GLsizei height,double scale)497 vgui_utils::set_glScissor(GLint x, GLint y, GLsizei width, GLsizei height, double scale)
498 {
499 get_gl_scale_default(scale);
500
501 glScissor(x * scale, y * scale, width * scale, height * scale);
502 }
503
504 /**
505 * Sets the line width and corrects for physical to logical scaling, so that the
506 * values are always in units of logical pixels, cross platform.
507 *
508 * @param width GLfloat width of lines drawn in logical pixels
509 * @param scale The scale factor used. Defaults to 0, meaning auto determine
510 * using vgui_adaptor::current. If this is not correct, the scale
511 * factor can manually be set
512 */
513 void
set_glLineWidth(GLfloat width,double scale)514 vgui_utils::set_glLineWidth(GLfloat width, double scale)
515 {
516 get_gl_scale_default(scale);
517 glLineWidth(scale * width);
518 }
519
520 /**
521 * Sets the point size and corrects for physical to logical scaling, so that the
522 * values are always in units of logical pixels, cross platform.
523 *
524 * @param size GLfloat width of dots drawn in logical pixels
525 * @param scale The scale factor used. Defaults to 0, meaning auto determine
526 * using vgui_adaptor::current. If this is not correct, the scale
527 * factor can manually be set
528 */
529 void
set_glPointSize(GLfloat size,double scale)530 vgui_utils::set_glPointSize(GLfloat size, double scale)
531 {
532 get_gl_scale_default(scale);
533 glPointSize(scale * size);
534 }
535
536 /**
537 * Sets the zoom factors and corrects for physical to logical scaling, so that
538 * the values are always in units of logical pixels, cross platform. It is less
539 * obvious why this needs a conversion. But adding the multiplier here, as long
540 * as set_glPixelZoom is called, the amount of zoom that is needed to fill the
541 * screen is added to the intended zoom, corrects the projection matrix, which
542 * compensated for the larger viewport used, and functions like glDrawPixels,
543 * glCopyPixels, etc... act in a DPI independent manner now. This means if you
544 * want the zoom to be "1" logically, you still have to call set_glPixelZoom(1),
545 * or else this correction will not be added.
546 *
547 * @param xfactor GLfloat horizontal zoom in logical pixels
548 * @param yfactor GLfloat vertical zoom in logical pixels
549 * @param scale The scale factor used. Defaults to 0, meaning auto determine
550 * using vgui_adaptor::current. If this is not correct, the scale
551 * factor can manually be set
552 */
553 void
set_glPixelZoom(GLfloat xfactor,GLfloat yfactor,double scale)554 vgui_utils::set_glPixelZoom(GLfloat xfactor, GLfloat yfactor, double scale)
555 {
556 get_gl_scale_default(scale);
557 glPixelZoom(scale * xfactor, scale * yfactor);
558 }
559
560 /**
561 * Draws a bitmaps corrects for physical to logical scaling, so that the values
562 * are always in units of logical pixels, cross platform. This is more complex
563 * than the other gl functions, as the bitmap is a raster in physical pixels,
564 * and actually needs to be resampled when scaled. The glRasterPos is in local
565 * (object) 3D coordinates, so it doesn't need to be scaled.
566 *
567 * @param width GLsizei width displayed of the bitmap (may be less than actual
568 * bitmap width which must me divisible by 8).
569 * @param height GLsizei height of the bitmap.
570 * @param xorig GLfloat offset of bitmap in window coordinates (logical)
571 * @param yorig GLfloat offset of bitmap in window coordinates (logical)
572 * @param xmove GLfloat offset of raster position after drawing in window
573 * coordinates (logical)
574 * @param ymove GLfloat offset of raster position after drawing in window
575 * coordinates (logical)
576 * @param bitmap GLubytes* the bitmap. This function supports a binary image
577 * bitmap using 1/2/4/8 packed bits.
578 * @param scale The scale factor used. Defaults to 0, meaning auto determine
579 * using vgui_adaptor::current. If this is not correct, the scale
580 * factor can manually be set
581 */
582 void
draw_glBitmap(GLsizei width,GLsizei height,GLfloat xorig,GLfloat yorig,GLfloat xmove,GLfloat ymove,const GLubyte * bitmap,double scale)583 vgui_utils::draw_glBitmap(GLsizei width,
584 GLsizei height,
585 GLfloat xorig,
586 GLfloat yorig,
587 GLfloat xmove,
588 GLfloat ymove,
589 const GLubyte * bitmap,
590 double scale)
591 {
592 GLint unpack_size;
593 glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_size);
594
595 // The real with is always divisible by 8, this is just how glBitmap works.
596 int remainder = width % 8;
597 if (remainder)
598 {
599 width += 8 - remainder;
600 }
601
602 get_gl_scale_default(scale);
603
604 if (scale == 1)
605 {
606 glBitmap(width, height, xorig, yorig, xmove, ymove, bitmap);
607 }
608 else
609 {
610 vil_image_view<bool> original_bitmap(width, height, 1);
611
612 int index = 0;
613 unsigned char mask0 = (0xff << (8 - unpack_size)) & 0xff;
614 unsigned char mask = mask0;
615
616 // Unpack into vil_image_view
617 for (int r = 0; r < height; r++)
618 {
619 for (int c = 0; c < width; c++)
620 {
621 original_bitmap(c, r, 0) = bitmap[index] & mask;
622 // Increment the mask
623 mask >>= unpack_size;
624 // If the mask is blank
625 if (!mask)
626 {
627 // reset the bitmask
628 mask = mask0;
629 // Go onto the next byte
630 ++index;
631 }
632 }
633 }
634
635 // Rescale mask
636 int width2 = width * scale;
637 int height2 = height * scale;
638 vil_image_view<bool> scaled_bitmap(width2, height2, 1);
639 vil_resample_nearest<bool, bool>(original_bitmap, scaled_bitmap, width2, height2);
640
641 // Make sure new width is divisible by 8 (support for fractional scales)
642 remainder = width2 % 8;
643 if (remainder)
644 {
645 width2 += 8 - remainder;
646 }
647
648 // Make new GLubyte array
649 std::vector<GLubyte> raster_scaled(width2 * height2, 0);
650
651 // repack into gl array.
652 int stride = width2 * unpack_size / 8;
653 for (int r = 0, index = 0; r < height2; r++, index = stride * r)
654 {
655 for (int c = 0; c < scaled_bitmap.ni(); c++)
656 {
657 if (scaled_bitmap(c, r, 0))
658 {
659 // sets all the bits (0xff) possible given the unpack size
660 raster_scaled[index] = raster_scaled[index] | (0xff & mask);
661 }
662
663 // Increment the mask
664 mask >>= unpack_size;
665 // If the mask is blank
666 if (!mask)
667 {
668 // reset the bitmask
669 mask = mask0;
670 // Go onto the next byte
671 ++index;
672 }
673 }
674 }
675 glBitmap(width2, height2, xorig * scale, yorig * scale, xmove * scale, ymove * scale, raster_scaled.data());
676 }
677 }
678