xref: /haiku/src/tests/kits/game/chart/ChartRender.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
1 /*
2 
3 	ChartRender.c
4 
5 	by Pierre Raynaud-Richard.
6 
7 	Copyright 1998 Be Incorporated, All Rights Reserved.
8 
9 */
10 
11 /* This file has been designed to be easy to compile as a stand-alone
12    piece of code, allowing you to use advanced intel compiler, even
13    if they are compatible with the whole Be environment. To accomplish
14    that purpose, all declarations were concentrated in ChartRender.h
15    (see that header file for more infos). */
16 #include "ChartRender.h"
17 
18 /* This table provide the horizontal and vertical offset of the matrix
19    of pixel used for drawing stars. This matrix is designed as follow:
20 
21     --  [00] [01] [02] [03]  --
22    [04] [05] [06] [07] [08] [09]
23    [10] [11] [12] [13] [14] [15]
24    [16] [17] [18] [19] [20] [21]
25    [22] [23] [24] [25] [26] [27]
26     --  [28] [29] [30] [31]  --
27 
28    The reference pixel is [12]. */
29 int8	pattern_dh[32] = {
30 		-1, 0, 1, 2,
31 	-2, -1, 0, 1, 2, 3,
32 	-2, -1, 0, 1, 2, 3,
33 	-2, -1, 0, 1, 2, 3,
34 	-2, -1, 0, 1, 2, 3,
35 		-1, 0, 1, 2
36 };
37 
38 int8	pattern_dv[32] = {
39 		-2, -2, -2, -2,
40 	-1, -1, -1, -1, -1, -1,
41 	0,	0,	0,	0,	0,	0,
42 	1,	1,	1,	1,	1,	1,
43 	2,	2,	2,	2,	2,	2,
44 		3,	3,	3,	3
45 };
46 
47 /* Those table contains a preprocessed version of the 32 size of star,
48    represented in the 32 pixels matrix, by alpha-blending density [0 to 7].
49    Those matrix are stored in packed format, as a the list of all pixel
50    whose alpha-blending density is > 0. There is 4 cases because every
51    star can be aligned at half a pixel in both direction (we implement
52    sub-pixel precision and anti-aliasing to reduce the jittering). */
53 static	uint8	pattern_list[4*LEVEL_COUNT][32];
54 static	uint8	pattern_list_count[4*LEVEL_COUNT];
55 static	uint8	pattern_color_offset[4*LEVEL_COUNT][32];
56 /* this table store the alpha-blending level of the center pixel. This
57    is used for size so small that only the center pixel is lighted. */
58 static	uint8	pixel_color_offset[LEVEL_COUNT];
59 
60 /* Those mask are use for fast clipping, to determine which of the 32
61    pixels of the standard star matrix are visible when coming closer
62    from a left, right, top or bottom clipping border. */
63 static uint32	visible_mask_left[6] = {
64 	0xffffffff,
65 	0xffbefbef,
66 	0xef3cf3ce,
67 	0xce38e38c,
68 	0x8c30c308,
69 	0x08208200
70 };
71 
72 static uint32	visible_mask_right[6] = {
73 	0xffffffff,
74 	0xf7df7dff,
75 	0x73cf3cf7,
76 	0x31c71c73,
77 	0x10c30c31,
78 	0x00410410,
79 };
80 
81 static uint32	visible_mask_top[6] = {
82 	0xffffffff,
83 	0xfffffff0,
84 	0xfffffc00,
85 	0xffff0000,
86 	0xffc00000,
87 	0xf0000000
88 };
89 
90 static uint32	visible_mask_bottom[6] = {
91 	0xffffffff,
92 	0x0fffffff,
93 	0x003fffff,
94 	0x0000ffff,
95 	0x000003ff,
96 	0x0000000f
97 };
98 
99 /* Private functions used only internally. */
100 float		b_sqrt(float x);
101 bool		ProjectStar(star *s, geometry *geo);
102 bool		CheckClipping(star *s, buffer *buf, bool reset_clipping);
103 void		DrawStar(star *s, buffer *buf);
104 void		EraseStar(star *s, buffer *buf);
105 
106 /* Good approximation of square root, for x > 0.0  That resolves
107    the problem of having a dependency with the math library, and
108    it's good enough for what we need. */
109 float b_sqrt(float x) {
110 	uint32			val;
111 	float			y,z,t;
112 	float	        flottant, tampon;
113 
114 	flottant = x;
115 	val = *((uint32*)&flottant);
116 	val >>= 1;
117 	val += 0x1FC00000L;
118 	*((uint32*)&tampon) = val;
119 	y = tampon;
120 	z = y*y+x;
121 	t = y*y-x;
122 	y *= (float)4.0;
123 	x = z*z;
124 	t = t*t;
125 	y = z*y;
126 	t = (float)2.0*x-t;
127 	return t/y;
128 }
129 
130 /* This function initialise the 32 sizes of anti-aliased star, each one
131    represented in 4 different half-pixel alignement :
132    x : -0.25, y : -0.25
133    x : +0.25, y : -0.25
134    x : -0.25, y : +0.25
135    x : +0.25, y : +0.25 */
136 void InitPatterns()
137 {
138 	int32		i, j, k, count;
139 	float		radius, x0, y0, x, y, dist, delta;
140 	uint8		color;
141 	uint8		*list, *color_offset;
142 
143 	/* do the 4 half-pixel alignement */
144 	for (j=0; j<4; j++) {
145 		if (j&1) x0 = 1.25;
146 		else	 x0 = 0.75;
147 		if (j&2) y0 = 1.25;
148 		else	 y0 = 0.75;
149 
150 		/* do the 32 sizes */
151 		for (i=0; i<LEVEL_COUNT; i++) {
152 			radius = (float)(i+1) * (2.8/(float)LEVEL_COUNT);
153 			count = 0;
154 			list = pattern_list[j*LEVEL_COUNT + i];
155 			color_offset = pattern_color_offset[j*LEVEL_COUNT + i];
156 
157 			/* scan the 32 pixels of the matrix */
158 			for (k=0; k<32; k++) {
159 				x = ((float)pattern_dh[k] + ROUNDING) - x0;
160 				y = ((float)pattern_dv[k] + ROUNDING) - y0;
161 
162 				dist = b_sqrt(x*x + y*y);
163 				/* process non source pixel */
164 				if (dist > 0.5) {
165 					delta = radius - dist + 0.5;
166 					if (delta >= 1.0) {
167 						*color_offset++ = 7;
168 						*list++ = k;
169 						count++;
170 					}
171 					else if (delta > 0.5) {
172 						*color_offset++ = (uint8)(7.499 - 16.0 * (1.0 - delta) * (1.0 - delta) + ROUNDING);
173 						*list++ = k;
174 						count++;
175 					}
176 					else if (delta > 0) {
177 						color = (uint8)(16.0 * delta * delta);
178 						if (color > 0) {
179 							*color_offset++ = color;
180 							*list++ = k;
181 							count++;
182 						}
183 					}
184 				}
185 				/* process source pixel (the one containing the center of the star) */
186 				else {
187 					if (radius < 0.25) {
188 						color = (uint8)(32.0 * radius * radius + ROUNDING);
189 						if (color == 0)
190 							color++;
191 					}
192 					else if (radius < 0.75) {
193 						delta = radius + 0.25;
194 						color = (uint8)(7.499 - 22.0 * (1.0 - delta) * (1.0 - delta) + ROUNDING);
195 					}
196 					else
197 						color = 7;
198 					*color_offset++ = color;
199 					*list++ = k;
200 					count++;
201 					pixel_color_offset[i] = color;
202 				}
203 			}
204 			pattern_list_count[j*LEVEL_COUNT + i] = count;
205 		}
206 	}
207 }
208 
209 /* Project a star (s) in the view space of the camera, as described by (geo).
210    Returns true if the star seems to be visible (in the pyramid of vision,
211    closer than the rear plan, farther than the front plan), or false if it's
212    clear that the star isnot visible. */
213 bool ProjectStar(star *s, geometry *geo)
214 {
215 	int32		h_double, v_double, level;
216 	float		x0, y0, z0, x, y, z, inv_z;
217 
218 	/* Calculate the coordinate of the star after doing the cycling operation
219 	   that convert the cube of the starfield in a torus. This ensure that
220 	   get the copy of the star that is the only one likely to be visible from
221 	   the camera. */
222 	x0 = s->x;
223 	if (x0 < geo->cutx)
224 		x0 += 1.0;
225 	y0 = s->y;
226 	if (y0 < geo->cuty)
227 		y0 += 1.0;
228 	z0 = s->z;
229 	if (z0 < geo->cutz)
230 		z0 += 1.0;
231 	/* Translate the star relative to the position of the camera. */
232 	x0 -= geo->x;
233 	y0 -= geo->y;
234 	z0 -= geo->z;
235 
236 	/* Calculate the z coordinate (depth) of the star in the camera referential. */
237 	z = geo->m[0][2]*x0 + geo->m[1][2]*y0 + geo->m[2][2]*z0;
238 
239 	/* Do the rear and front plan clipping */
240 	if ((z < geo->z_min) || (z > geo->z_max))
241 		return false;
242 
243 	/* Calculate the x coordinate (horizontal) of the star in the camera referential. */
244 	x = geo->m[0][0]*x0 + geo->m[1][0]*y0 + geo->m[2][0]*z0;
245 
246 	/* Do the left and right clipping based on the pyramid of vision. */
247 	if ((x < geo->xz_min*z-BORDER_CLIPPING) || (x > geo->xz_max*z+BORDER_CLIPPING))
248 		return false;
249 
250 	/* Calculate the y coordinate (vertical) of the star in the camera referential. */
251 	y = geo->m[0][1]*x0 + geo->m[1][1]*y0 + geo->m[2][1]*z0;
252 
253 	/* Do the top and bottom clipping based on the pyramid of vision. */
254 	if ((y < geo->yz_min*z-BORDER_CLIPPING) || (y > geo->yz_max*z+BORDER_CLIPPING))
255 		return false;
256 
257 	/* Calculate the invert of z, used to project both H and V coordinate. Apply
258 	   the zoom-factor at the same time. The zoom-factor was overscale by a factor
259 	   of two in advance, for the half-pixel precision processing */
260 	inv_z = geo->zoom_factor/z;
261 
262 	/* Calculate the double pixel coordinate in the buffer (in half-pixel). */
263 	h_double = (int32)(x * inv_z + geo->offset_h);
264 	v_double = (int32)(y * inv_z + geo->offset_v);
265 
266 	/* Calculate the light level of the star. We use that little weird function
267 	   to a get faster gradient to black near the rear plan. */
268 	level = (int32)(s->size * (inv_z * geo->z_max_square - z * geo->zoom_factor)) >> 8;
269 	/* The light level can go higher that our max (saturation). */
270 	if (level >= LEVEL_COUNT)
271 		level = LEVEL_COUNT-1;
272 
273 	/* Get the real pixel coordinate in the buffer from the double coordinates */
274 	s->h = h_double >> 1;
275 	s->v = v_double >> 1;
276 	/* Save the light level (used to recognize single pixel star) */
277 	s->level = level;
278 	/* switch between the 4 pattern table use for the 4 half-aligned. */
279 	if ((h_double & 1) == 1) level += LEVEL_COUNT;
280 	if ((v_double & 1) == 1) level += 2*LEVEL_COUNT;
281 	s->pattern_level = level;
282 	return true;
283 }
284 
285 /* Once a star has been projected (using ProjectStar), we need to determine
286    which pixel of the star matrix are visible (if any). This depend of the
287    clipping of the specific buffer you're using. This function will do that
288    for the star (s), in the buffer (buf). It will return false if the star
289    is fully invisible, true if not. The falg reset_clipping is used to
290    reprocess the clipping from scratsh, or to just cumulate the new clipping
291    to the last drawing clipping (this is needed when updating the clipping
292    of every stars after changing the clipping region of the buffer). */
293 bool CheckClipping(star *s, buffer *buf, bool reset_clipping)
294 {
295 	int32			delta;
296 	uint32			i, total_visible, tmp_visible;
297 	clipping_rect	box;
298 	clipping_rect	*r;
299 
300 	/* Simple case : the star is represented by only one pixel. */
301 	if (pattern_list_count[s->pattern_level] == 1) {
302 		/* if the pixel is not in the bounding box of the clipping region,
303 		   the star is guarantee to be invisible. */
304 		if ((s->h < buf->clip_bounds.left) ||
305 			(s->h > buf->clip_bounds.right) ||
306 			(s->v < buf->clip_bounds.top) ||
307 			(s->v > buf->clip_bounds.bottom))
308 			goto invisible;
309 		/* if the clipping region contains only one rectangle, then it's
310 		   equal to its bounding box, so no further test are needed. */
311 		if (buf->clip_list_count == 1)
312 			goto visible;
313 		/* In the other case, we need to go through the list of rectangle
314 		   of the clipping region and check if the pixel is in any of those */
315 		r = buf->clip_list;
316 		for (i=0; i<buf->clip_list_count; r++, i++)
317 			if ((s->h >= r->left) &&
318 				(s->h <= r->right) &&
319 				(s->v >= r->top) &&
320 				(s->v <= r->bottom))
321 				goto visible;
322 		/* The pixel is not visible. The star is marked as not drawn. */
323 	invisible:
324 		s->last_draw_offset = INVALID;
325 		return false;
326 	visible:
327 		/* The pixel is visible. The offset at which the star should be draw is
328 		   calculated and store for using by drawing (and erasing later). */
329 		s->last_draw_offset = s->v * buf->bytes_per_row + s->h * buf->bytes_per_pixel;
330 		return true;
331 	}
332 	/* Complex case : the star is represented by more than one pixel. */
333 	else {
334 		/* Calculate the box the bounding box of the matrix of 32 pixels used
335 		   to represent the star, called box. */
336 		box.left = s->h - 2;
337 		box.right = s->h + 3;
338 		box.top = s->v - 2;
339 		box.bottom = s->v + 3;
340 
341 		/* Check if the box is fully outside of the bounding box of the clipping
342 		   region. That woudl guarantee that the star is invisible. */
343 		if ((box.right < buf->clip_bounds.left) ||
344 			(box.left > buf->clip_bounds.right) ||
345 			(box.bottom < buf->clip_bounds.top) ||
346 			(box.top > buf->clip_bounds.bottom))
347 			goto invisible_pat;
348 
349 		/* Now, we have to go through the list of rectangle of the clipping region
350 		   and cumulate the mask of the star matrix pixels that are visible in any
351 		   of those rectangle. At start time, the mask is empty. */
352 		total_visible = 0;
353 		r = buf->clip_list;
354 		for (i=0; i<buf->clip_list_count; r++, i++) {
355 			/* When reseting the clipping, all pixel of the matrix are tested. In
356 			   the other mode, only the pixel previously visible are tested (as we
357 			   want to know which one of the previously drawn pixel still need to
358 			   be erased. */
359 			if (reset_clipping)
360 				tmp_visible = 0xffffffff;
361 			else
362 				tmp_visible = s->last_draw_pattern;
363 
364 			/* Calculate the clipping on the left side of the rectangle. */
365 			delta = r->left-box.left;
366 			if (delta > 5)
367 				continue;
368 			if (delta > 0)
369 				tmp_visible &= visible_mask_left[delta];
370 
371 			/* Calculate the clipping on the right side of the rectangle. */
372 			delta = box.right-r->right;
373 			if (delta > 5)
374 				continue;
375 			if (delta > 0)
376 				tmp_visible &= visible_mask_right[delta];
377 
378 			/* Calculate the clipping on the top side of the rectangle. */
379 			delta = r->top-box.top;
380 			if (delta > 5)
381 				continue;
382 			if (delta > 0)
383 				tmp_visible &= visible_mask_top[delta];
384 
385 			/* Calculate the clipping on the bottom side of the rectangle. */
386 			delta = box.bottom-r->bottom;
387 			if (delta > 5)
388 				continue;
389 			if (delta > 0)
390 				tmp_visible &= visible_mask_bottom[delta];
391 
392 			/* Pixel of the matrix not clipped out at that point are visible
393 			   inside this rectangle of the clipping region. We need to add
394 			   them to the mask of currently known visible pixel. */
395 			total_visible |= tmp_visible;
396 			/* If all pixel of the matrix are already visible, no need to continue
397 			   further. */
398 			if (total_visible == 0xffffffff)
399 				goto visible_pat;
400 		}
401 		/* If no pixel are visible, then we know... */
402 		if (total_visible != 0)
403 			goto visible_pat;
404 
405 		/* The star is not visible. It's marked as not drawn. */
406 	invisible_pat:
407 		s->last_draw_offset = INVALID;
408 		return false;
409 	visible_pat:
410 		/* The star is partially visible. The offset at which the star should be
411 		   draw is calculated and store for using by drawing (and erasing later).
412 		   The mask of which pixel of the matrix are visible is store for use
413 		   at drawing and erasing time. */
414 		s->last_draw_offset = s->v * buf->bytes_per_row + s->h * buf->bytes_per_pixel;
415 		s->last_draw_pattern = total_visible;
416 		return true;
417 	}
418 }
419 
420 /* After calling ProjectStar and CheckClipping, we're finally ready to
421    draw the star in its destination buffer. So let's do it... */
422 void DrawStar(star *s, buffer *buf)
423 {
424 	int32		i, index, count;
425 	uint8		*draw8;
426 	uint16		*draw16;
427 	uint32		*draw32;
428 	uint32		*colors;
429 	uint8		*pat_list;
430 	uint8		*pat_color_offset;
431 
432 	/* Simple case : the star is represented by only one pixel. */
433 	count = pattern_list_count[s->pattern_level];
434 	if (count == 1) {
435 		/* Depending the depth mode of the drawing buffer... */
436 		switch (buf->depth_mode) {
437 		case PIXEL_1_BYTE :
438 			/* Get the pointer to the address we want to draw to... */
439 			draw8 = (uint8*)((char*)buf->bits + s->last_draw_offset);
440 			/* ... and write the color pattern we want to use depending of
441 			   the lighting level and the color scheme of the star. */
442 			*draw8 = buf->colors[s->color_type][pixel_color_offset[s->level]];
443 			break;
444 		case PIXEL_2_BYTES :
445 			/* Same thing for 2 bytes mode */
446 			draw16 = (uint16*)((char*)buf->bits + s->last_draw_offset);
447 			*draw16 = buf->colors[s->color_type][pixel_color_offset[s->level]];
448 			break;
449 		case PIXEL_4_BYTES :
450 			/* Same thing for 4 bytes mode */
451 			draw32 = (uint32*)((char*)buf->bits + s->last_draw_offset);
452 			*draw32 = buf->colors[s->color_type][pixel_color_offset[s->level]];
453 			break;
454 		}
455 	}
456 	/* Complex case : the star is represented by a multiple pixels. */
457 	else {
458 		/* Pointer to the color table used depending the color scheme of
459 		   the star. */
460 		colors = buf->colors[s->color_type];
461 		pat_list = pattern_list[s->pattern_level];
462 		pat_color_offset = pattern_color_offset[s->pattern_level];
463 
464 		/* Plot all pixel used to represent the star one after one... */
465 		for (i=0; i<count; i++) {
466 			/* This is the index of the pixel in the matrix */
467 			index = pat_list[i];
468 			/* Check if this pixel is visible (using the result of the clipping) */
469 			if (s->last_draw_pattern & (1<<index)) {
470 				switch (buf->depth_mode) {
471 				case PIXEL_1_BYTE :
472 					/* Get the pointer to the address we want to draw to... */
473 					draw8 = (uint8*)((char*)buf->pattern_bits[index] + s->last_draw_offset);
474 					/* ... and write the color pattern we want to use depending of
475 					   the lighting level and the color scheme of the star. */
476 					*draw8 = colors[pat_color_offset[i]];
477 					break;
478 				case PIXEL_2_BYTES :
479 					/* Same thing for 2 bytes mode */
480 					draw16 = (uint16*)((char*)buf->pattern_bits[index] + s->last_draw_offset);
481 					*draw16 = colors[pat_color_offset[i]];
482 					break;
483 				case PIXEL_4_BYTES :
484 					/* Same thing for 4 bytes mode */
485 					draw32 = (uint32*)((char*)buf->pattern_bits[index] + s->last_draw_offset);
486 					*draw32 = colors[pat_color_offset[i]];
487 					break;
488 				}
489 			}
490 		}
491 	}
492 }
493 
494 /* Before redrawing a star at its new position, we need to erase what we draw
495    at the previous frame... */
496 void EraseStar(star *s, buffer *buf)
497 {
498 	int32		i, index, count;
499 	uint8		*draw8;
500 	uint16		*draw16;
501 	uint32		*draw32;
502 	uint32		back_color;
503 	uint8		*pat_list;
504 
505 	/* Color pattern we use to erase the buffer. */
506 	back_color = buf->back_color;
507 
508 	/* Simple case : the star is represented by only one pixel. */
509 	count = pattern_list_count[s->pattern_level];
510 	if (count == 1) {
511 		/* Depending the depth mode of the drawing buffer... */
512 		switch (buf->depth_mode) {
513 		case PIXEL_1_BYTE :
514 			/* Get the pointer to the address we want to erase... */
515 			draw8 = (uint8*)((char*)buf->bits + s->last_draw_offset);
516 			/* ... and write the background color pattern. */
517 			*draw8 = back_color;
518 			break;
519 		case PIXEL_2_BYTES :
520 			/* Same thing for 2 bytes mode */
521 			draw16 = (uint16*)((char*)buf->bits + s->last_draw_offset);
522 			*draw16 = back_color;
523 			break;
524 		case PIXEL_4_BYTES :
525 			/* Same thing for 4 bytes mode */
526 			draw32 = (uint32*)((char*)buf->bits + s->last_draw_offset);
527 			*draw32 = back_color;
528 			break;
529 		}
530 	}
531 	/* Complex case : the star is represented by a multiple pixels. */
532 	else {
533 		pat_list = pattern_list[s->pattern_level];
534 
535 		/* Erase all pixel used to represent the star one after one... */
536 		for (i=0; i<count; i++) {
537 			index = pat_list[i];
538 			/* Check if this pixel is visible (using the result of the clipping) */
539 			if (s->last_draw_pattern & (1<<index)) {
540 				switch (buf->depth_mode) {
541 				case PIXEL_1_BYTE :
542 					/* Get the pointer to the address we want to draw to... */
543 					draw8 = (uint8*)((char*)buf->pattern_bits[index] + s->last_draw_offset);
544 					/* ... and write the background color pattern. */
545 					*draw8 = back_color;
546 					break;
547 				case PIXEL_2_BYTES :
548 					/* Same thing for 2 bytes mode */
549 					draw16 = (uint16*)((char*)buf->pattern_bits[index] + s->last_draw_offset);
550 					*draw16 = back_color;
551 					break;
552 				case PIXEL_4_BYTES :
553 					/* Same thing for 4 bytes mode */
554 					draw32 = (uint32*)((char*)buf->pattern_bits[index] + s->last_draw_offset);
555 					*draw32 = back_color;
556 					break;
557 				}
558 			}
559 		}
560 	}
561 }
562 
563 /* This function do the transition from previous state to the new state
564    as described in (geo), in the buffer (buf), for the list of star (sp) */
565 void RefreshStarPacket(buffer *buf, star_packet *sp, geometry *geo)
566 {
567 	int32			i, min_count;
568 	star			*s;
569 
570 	/* Calculate the number of stars that were process during the
571 	   previous frame and still need to be process for that frame. */
572 	min_count = sp->erase_count;
573 	if (sp->count < min_count)
574 		min_count = sp->count;
575 
576 	s = sp->list;
577 
578 	/* For all those star... */
579 	for (i=0; i<min_count; s++, i++) {
580 		/* ... erase them if necessary, ... */
581 		if (s->last_draw_offset != INVALID)
582 			EraseStar(s, buf);
583 		/* ... project them at their new position, ... */
584 		if (ProjectStar(s, geo)) {
585 			/* ... check the clipping of the buffer if the star are in
586 			   the pyramid of vision, ... */
587 			if (CheckClipping(s, buf, true))
588 				/* ... and draw them if they're really visible. */
589 				DrawStar(s, buf);
590 		}
591 		/* ... or mark them as invisible if they're not in the pyramid
592 		   of vision. */
593 		else
594 			s->last_draw_offset = INVALID;
595 	}
596 
597 	/* For star that were process at the previous frame but that we don't
598 	   want to process anymore, we just need to erase them. */
599 	for (; i<sp->erase_count; s++, i++)
600 		if (s->last_draw_offset != INVALID)
601 			EraseStar(s, buf);
602 
603 	/* For star that were not process before, but are now, we just need to
604 	   go through the projection, clipping and drawing steps. */
605 	for (; i<sp->count; s++, i++) {
606 		if (ProjectStar(s, geo)) {
607 			if (CheckClipping(s, buf, true))
608 				DrawStar(s, buf);
609 		}
610 		else
611 			s->last_draw_offset = INVALID;
612 	}
613 }
614 
615 /* Update the clipping visibility of all star of the list (sp) to
616   respect the new clipping defined for the buffer (buf). */
617 void RefreshClipping(buffer *buf, star_packet *sp)
618 {
619 	star		*s;
620 	int32		i;
621 
622 	s = sp->list;
623 	for (i=0; i<sp->erase_count; s++, i++)
624 		if (s->last_draw_offset != INVALID)
625 			CheckClipping(s, buf, false);
626 }
627 
628 
629