Renamed softpipe directories and files to something less confusing.
[mesa.git] / src / mesa / pipe / softpipe / sp_prim_setup.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /* Authors: Keith Whitwell <keith@tungstengraphics.com>
29 */
30
31 #include "imports.h"
32 #include "macros.h"
33
34 #include "sp_context.h"
35 #include "sp_prim.h"
36 #include "sp_tile.h"
37
38
39 /**
40 * Triangle edge info
41 */
42 struct edge {
43 GLfloat dx; /* X(v1) - X(v0), used only during setup */
44 GLfloat dy; /* Y(v1) - Y(v0), used only during setup */
45 GLfloat dxdy; /* dx/dy */
46 GLfloat sx; /* first sample point x coord */
47 GLfloat sy;
48 GLint lines; /* number of lines on this edge */
49 };
50
51
52 /**
53 * Triangle setup info (derived from prim_stage).
54 * Also used for line drawing (taking some liberties).
55 */
56 struct setup_stage {
57 struct prim_stage stage; /**< This must be first */
58
59 /* Vertices are just an array of floats making up each attribute in
60 * turn. Currently fixed at 4 floats, but should change in time.
61 * Codegen will help cope with this.
62 */
63 const struct vertex_header *vmax;
64 const struct vertex_header *vmid;
65 const struct vertex_header *vmin;
66 const struct vertex_header *vprovoke;
67
68 struct edge ebot;
69 struct edge etop;
70 struct edge emaj;
71
72 GLfloat oneoverarea;
73
74 struct setup_coefficient coef[FRAG_ATTRIB_MAX];
75 struct quad_header quad;
76
77 struct {
78 GLint left[2]; /**< [0] = row0, [1] = row1 */
79 GLint right[2];
80 GLint y;
81 GLuint y_flags;
82 GLuint mask; /**< mask of MASK_BOTTOM/TOP_LEFT/RIGHT bits */
83 } span;
84 };
85
86
87
88 /**
89 * Basically a cast wrapper.
90 */
91 static inline struct setup_stage *setup_stage( struct prim_stage *stage )
92 {
93 return (struct setup_stage *)stage;
94 }
95
96
97 /**
98 * Given an X or Y coordinate, return the block/quad coordinate that it
99 * belongs to.
100 */
101 static inline GLint block( GLint x )
102 {
103 return x & ~1;
104 }
105
106
107
108 static void setup_begin( struct prim_stage *stage )
109 {
110 setup_stage(stage)->quad.nr_attrs = stage->softpipe->nr_frag_attrs;
111 }
112
113
114 /**
115 * Run shader on a quad/block.
116 */
117 static void run_shader_block( struct setup_stage *setup,
118 GLint x, GLint y, GLuint mask )
119 {
120 setup->quad.x0 = x;
121 setup->quad.y0 = y;
122 setup->quad.mask = mask;
123
124 quad_shade( setup->stage.softpipe, &setup->quad );
125 }
126
127
128 /**
129 * Compute mask which indicates which pixels in the 2x2 quad are actually inside
130 * the triangle's bounds.
131 *
132 * this is pretty nasty... may need to rework flush_spans again to
133 * fix it, if possible.
134 */
135 static GLuint calculate_mask( struct setup_stage *setup,
136 GLint x )
137 {
138 GLuint mask = 0;
139
140 if (x >= setup->span.left[0] && x < setup->span.right[0])
141 mask |= MASK_BOTTOM_LEFT;
142
143 if (x >= setup->span.left[1] && x < setup->span.right[1])
144 mask |= MASK_TOP_LEFT;
145
146 if (x+1 >= setup->span.left[0] && x+1 < setup->span.right[0])
147 mask |= MASK_BOTTOM_RIGHT;
148
149 if (x+1 >= setup->span.left[1] && x+1 < setup->span.right[1])
150 mask |= MASK_TOP_RIGHT;
151
152 return mask;
153 }
154
155
156 /**
157 * Render a horizontal span of quads
158 */
159 static void flush_spans( struct setup_stage *setup )
160 {
161 GLint minleft, maxright;
162 GLint x;
163
164 switch (setup->span.y_flags) {
165 case 3:
166 minleft = MIN2(setup->span.left[0], setup->span.left[1]);
167 maxright = MAX2(setup->span.right[0], setup->span.right[1]);
168 break;
169
170 case 1:
171 minleft = setup->span.left[0];
172 maxright = setup->span.right[0];
173 break;
174
175 case 2:
176 minleft = setup->span.left[1];
177 maxright = setup->span.right[1];
178 break;
179
180 default:
181 return;
182 }
183
184
185 for (x = block(minleft); x <= block(maxright); )
186 {
187 run_shader_block( setup, x,
188 setup->span.y,
189 calculate_mask( setup, x ) );
190 x += 2;
191 }
192
193 setup->span.y = 0;
194 setup->span.y_flags = 0;
195 setup->span.right[0] = 0;
196 setup->span.right[1] = 0;
197 }
198
199
200 static GLboolean setup_sort_vertices( struct setup_stage *setup,
201 const struct prim_header *prim )
202 {
203 const struct vertex_header *v0 = prim->v[0];
204 const struct vertex_header *v1 = prim->v[1];
205 const struct vertex_header *v2 = prim->v[2];
206
207 setup->vprovoke = v2;
208
209 /* determine bottom to top order of vertices */
210 {
211 GLfloat y0 = v0->data[0][1];
212 GLfloat y1 = v1->data[0][1];
213 GLfloat y2 = v2->data[0][1];
214 if (y0 <= y1) {
215 if (y1 <= y2) {
216 /* y0<=y1<=y2 */
217 setup->vmin = v0;
218 setup->vmid = v1;
219 setup->vmax = v2;
220 }
221 else if (y2 <= y0) {
222 /* y2<=y0<=y1 */
223 setup->vmin = v2;
224 setup->vmid = v0;
225 setup->vmax = v1;
226 }
227 else {
228 /* y0<=y2<=y1 */
229 setup->vmin = v0;
230 setup->vmid = v2;
231 setup->vmax = v1;
232 }
233 }
234 else {
235 if (y0 <= y2) {
236 /* y1<=y0<=y2 */
237 setup->vmin = v1;
238 setup->vmid = v0;
239 setup->vmax = v2;
240 }
241 else if (y2 <= y1) {
242 /* y2<=y1<=y0 */
243 setup->vmin = v2;
244 setup->vmid = v1;
245 setup->vmax = v0;
246 }
247 else {
248 /* y1<=y2<=y0 */
249 setup->vmin = v1;
250 setup->vmid = v2;
251 setup->vmax = v0;
252 }
253 }
254 }
255
256 setup->ebot.dx = setup->vmid->data[0][0] - setup->vmin->data[0][0];
257 setup->ebot.dy = setup->vmid->data[0][1] - setup->vmin->data[0][1];
258 setup->emaj.dx = setup->vmax->data[0][0] - setup->vmin->data[0][0];
259 setup->emaj.dy = setup->vmax->data[0][1] - setup->vmin->data[0][1];
260 setup->etop.dx = setup->vmax->data[0][0] - setup->vmid->data[0][0];
261 setup->etop.dy = setup->vmax->data[0][1] - setup->vmid->data[0][1];
262
263 /* xxx: may need to adjust this sign according to the if-tree
264 * above:
265 *
266 * XXX: this is like 'det', but calculated from screen coords??
267 */
268 {
269 const GLfloat area = (setup->emaj.dx * setup->ebot.dy -
270 setup->ebot.dx * setup->emaj.dy);
271
272 setup->oneoverarea = 1.0 / area;
273 }
274
275 /* XXX need to know if this is a front or back-facing triangle:
276 * - the GLSL gl_FrontFacing fragment attribute (bool)
277 * - two-sided stencil test
278 */
279 setup->quad.facing = 0;
280
281 _mesa_printf("%s one-over-area %f\n", __FUNCTION__, setup->oneoverarea );
282
283
284 return GL_TRUE;
285 }
286
287
288 /**
289 * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
290 */
291 static void const_coeff( struct setup_stage *setup,
292 GLuint slot,
293 GLuint i )
294 {
295 setup->coef[slot].dadx[i] = 0;
296 setup->coef[slot].dady[i] = 0;
297
298 /* need provoking vertex info!
299 */
300 setup->coef[slot].a0[i] = setup->vprovoke->data[slot][i];
301 }
302
303
304 /**
305 * Compute a0, dadx and dady for a linearly interpolated coefficient,
306 * for a triangle.
307 */
308 static void tri_linear_coeff( struct setup_stage *setup,
309 GLuint slot,
310 GLuint i)
311 {
312 GLfloat botda = setup->vmid->data[slot][i] - setup->vmin->data[slot][i];
313 GLfloat majda = setup->vmax->data[slot][i] - setup->vmin->data[slot][i];
314 GLfloat a = setup->ebot.dy * majda - botda * setup->emaj.dy;
315 GLfloat b = setup->emaj.dx * botda - majda * setup->ebot.dx;
316
317 setup->coef[slot].dadx[i] = a * setup->oneoverarea;
318 setup->coef[slot].dady[i] = b * setup->oneoverarea;
319
320 /* calculate a0 as the value which would be sampled for the
321 * fragment at (0,0), taking into account that we want to sample at
322 * pixel centers, in other words (0.5, 0.5).
323 *
324 * this is neat but unfortunately not a good way to do things for
325 * triangles with very large values of dadx or dady as it will
326 * result in the subtraction and re-addition from a0 of a very
327 * large number, which means we'll end up loosing a lot of the
328 * fractional bits and precision from a0. the way to fix this is
329 * to define a0 as the sample at a pixel center somewhere near vmin
330 * instead - i'll switch to this later.
331 */
332 setup->coef[slot].a0[i] = (setup->vmin->data[slot][i] -
333 (setup->coef[slot].dadx[i] * (setup->vmin->data[0][0] - 0.5) +
334 setup->coef[slot].dady[i] * (setup->vmin->data[0][1] - 0.5)));
335
336 _mesa_printf("attr[%d].%c: %f dx:%f dy:%f\n",
337 slot, "xyzw"[i],
338 setup->coef[slot].a0[i],
339 setup->coef[slot].dadx[i],
340 setup->coef[slot].dady[i]);
341 }
342
343
344 /**
345 * Compute a0, dadx and dady for a perspective-corrected interpolant,
346 * for a triangle.
347 */
348 static void tri_persp_coeff( struct setup_stage *setup,
349 GLuint slot,
350 GLuint i )
351 {
352 /* premultiply by 1/w:
353 */
354 GLfloat mina = setup->vmin->data[slot][i] * setup->vmin->data[0][3];
355 GLfloat mida = setup->vmid->data[slot][i] * setup->vmid->data[0][3];
356 GLfloat maxa = setup->vmax->data[slot][i] * setup->vmax->data[0][3];
357
358 GLfloat botda = mida - mina;
359 GLfloat majda = maxa - mina;
360 GLfloat a = setup->ebot.dy * majda - botda * setup->emaj.dy;
361 GLfloat b = setup->emaj.dx * botda - majda * setup->ebot.dx;
362
363 setup->coef[slot].dadx[i] = a * setup->oneoverarea;
364 setup->coef[slot].dady[i] = b * setup->oneoverarea;
365 setup->coef[slot].a0[i] = (mina -
366 (setup->coef[slot].dadx[i] * (setup->vmin->data[0][0] - 0.5) +
367 setup->coef[slot].dady[i] * (setup->vmin->data[0][1] - 0.5)));
368 }
369
370
371
372 /**
373 * Compute the setup->coef[] array dadx, dady, a0 values.
374 * Must be called after setup->vmin,vmid,vmax,vprovoke are initialized.
375 */
376 static void setup_tri_coefficients( struct setup_stage *setup )
377 {
378 const enum interp_mode *interp = setup->stage.softpipe->interp;
379 GLuint slot, j;
380
381 /* z and w are done by linear interpolation:
382 */
383 tri_linear_coeff(setup, 0, 2);
384 tri_linear_coeff(setup, 0, 3);
385
386 /* setup interpolation for all the remaining attributes:
387 */
388 for (slot = 1; slot < setup->quad.nr_attrs; slot++) {
389 switch (interp[slot]) {
390 case INTERP_CONSTANT:
391 for (j = 0; j < NUM_CHANNELS; j++)
392 const_coeff(setup, slot, j);
393 break;
394
395 case INTERP_LINEAR:
396 for (j = 0; j < NUM_CHANNELS; j++)
397 tri_linear_coeff(setup, slot, j);
398 break;
399
400 case INTERP_PERSPECTIVE:
401 for (j = 0; j < NUM_CHANNELS; j++)
402 tri_persp_coeff(setup, slot, j);
403 break;
404 }
405 }
406 }
407
408
409
410 static void setup_tri_edges( struct setup_stage *setup )
411 {
412 GLfloat vmin_x = setup->vmin->data[0][0] + 0.5;
413 GLfloat vmid_x = setup->vmid->data[0][0] + 0.5;
414
415 GLfloat vmin_y = setup->vmin->data[0][1] - 0.5;
416 GLfloat vmid_y = setup->vmid->data[0][1] - 0.5;
417 GLfloat vmax_y = setup->vmax->data[0][1] - 0.5;
418
419 setup->emaj.sy = ceilf(vmin_y);
420 setup->emaj.lines = (GLint) ceilf(vmax_y - setup->emaj.sy);
421 setup->emaj.dxdy = setup->emaj.dx / setup->emaj.dy;
422 setup->emaj.sx = vmin_x + (setup->emaj.sy - vmin_y) * setup->emaj.dxdy;
423
424 setup->etop.sy = ceilf(vmid_y);
425 setup->etop.lines = (GLint) ceilf(vmax_y - setup->etop.sy);
426 setup->etop.dxdy = setup->etop.dx / setup->etop.dy;
427 setup->etop.sx = vmid_x + (setup->etop.sy - vmid_y) * setup->etop.dxdy;
428
429 setup->ebot.sy = ceilf(vmin_y);
430 setup->ebot.lines = (GLint) ceilf(vmid_y - setup->ebot.sy);
431 setup->ebot.dxdy = setup->ebot.dx / setup->ebot.dy;
432 setup->ebot.sx = vmin_x + (setup->ebot.sy - vmin_y) * setup->ebot.dxdy;
433 }
434
435
436 /**
437 * Render the upper or lower half of a triangle.
438 * Scissoring is applied here too.
439 */
440 static void subtriangle( struct setup_stage *setup,
441 struct edge *eleft,
442 struct edge *eright,
443 GLuint lines )
444 {
445 GLint y, start_y, finish_y;
446 GLint sy = (GLint)eleft->sy;
447
448 assert((GLint)eleft->sy == (GLint) eright->sy);
449 assert((GLint)eleft->sy >= 0); /* catch bug in x64? */
450
451 /* scissor y:
452 */
453 if (setup->stage.softpipe->setup.scissor) {
454 start_y = sy;
455 finish_y = start_y + lines;
456
457 if (start_y < setup->stage.softpipe->scissor.miny)
458 start_y = setup->stage.softpipe->scissor.miny;
459
460 if (finish_y > setup->stage.softpipe->scissor.maxy)
461 finish_y = setup->stage.softpipe->scissor.maxy;
462
463 start_y -= sy;
464 finish_y -= sy;
465 }
466 else {
467 start_y = 0;
468 finish_y = lines;
469 }
470
471 _mesa_printf("%s %d %d\n", __FUNCTION__, start_y, finish_y);
472
473 for (y = start_y; y < finish_y; y++) {
474
475 /* avoid accumulating adds as floats don't have the precision to
476 * accurately iterate large triangle edges that way. luckily we
477 * can just multiply these days.
478 *
479 * this is all drowned out by the attribute interpolation anyway.
480 */
481 GLint left = (GLint)(eleft->sx + y * eleft->dxdy);
482 GLint right = (GLint)(eright->sx + y * eright->dxdy);
483
484 /* scissor x:
485 */
486 if (setup->stage.softpipe->setup.scissor) {
487 if (left < setup->stage.softpipe->scissor.minx)
488 left = setup->stage.softpipe->scissor.minx;
489
490 if (right > setup->stage.softpipe->scissor.maxx)
491 right = setup->stage.softpipe->scissor.maxx;
492 }
493
494 if (left < right) {
495 GLint _y = sy+y;
496 if (block(_y) != setup->span.y) {
497 flush_spans(setup);
498 setup->span.y = block(_y);
499 }
500
501 setup->span.left[_y&1] = left;
502 setup->span.right[_y&1] = right;
503 setup->span.y_flags |= 1<<(_y&1);
504 }
505 }
506
507
508 /* save the values so that emaj can be restarted:
509 */
510 eleft->sx += lines * eleft->dxdy;
511 eright->sx += lines * eright->dxdy;
512 eleft->sy += lines;
513 eright->sy += lines;
514 }
515
516
517 /**
518 * Do setup for triangle rasterization, then render the triangle.
519 */
520 static void setup_tri( struct prim_stage *stage,
521 struct prim_header *prim )
522 {
523 struct setup_stage *setup = setup_stage( stage );
524
525 _mesa_printf("%s\n", __FUNCTION__ );
526
527 setup_sort_vertices( setup, prim );
528 setup_tri_coefficients( setup );
529 setup_tri_edges( setup );
530
531 setup->span.y = 0;
532 setup->span.y_flags = 0;
533 setup->span.right[0] = 0;
534 setup->span.right[1] = 0;
535 // setup->span.z_mode = tri_z_mode( setup->ctx );
536
537 // init_constant_attribs( setup );
538
539 if (setup->oneoverarea < 0.0) {
540 /* emaj on left:
541 */
542 subtriangle( setup, &setup->emaj, &setup->ebot, setup->ebot.lines );
543 subtriangle( setup, &setup->emaj, &setup->etop, setup->etop.lines );
544 }
545 else {
546 /* emaj on right:
547 */
548 subtriangle( setup, &setup->ebot, &setup->emaj, setup->ebot.lines );
549 subtriangle( setup, &setup->etop, &setup->emaj, setup->etop.lines );
550 }
551
552 flush_spans( setup );
553 }
554
555
556
557 /**
558 * Compute a0, dadx and dady for a linearly interpolated coefficient,
559 * for a line.
560 */
561 static void
562 line_linear_coeff(struct setup_stage *setup, GLuint slot, GLuint i)
563 {
564 const GLfloat dz = setup->vmax->data[slot][i] - setup->vmin->data[slot][i];
565 const GLfloat dadx = dz * setup->emaj.dx * setup->oneoverarea;
566 const GLfloat dady = dz * setup->emaj.dy * setup->oneoverarea;
567 setup->coef[slot].dadx[i] = dadx;
568 setup->coef[slot].dady[i] = dady;
569 setup->coef[slot].a0[i]
570 = (setup->vmin->data[slot][i] -
571 (dadx * (setup->vmin->data[0][0] - 0.5) +
572 dady * (setup->vmin->data[0][1] - 0.5)));
573 }
574
575
576 /**
577 * Compute a0, dadx and dady for a perspective-corrected interpolant,
578 * for a line.
579 */
580 static void
581 line_persp_coeff(struct setup_stage *setup, GLuint slot, GLuint i)
582 {
583 /* XXX to do */
584 line_linear_coeff(setup, slot, i); /* XXX temporary */
585 }
586
587
588 /**
589 * Compute the setup->coef[] array dadx, dady, a0 values.
590 * Must be called after setup->vmin,vmax are initialized.
591 */
592 static INLINE void
593 setup_line_coefficients(struct setup_stage *setup, struct prim_header *prim)
594 {
595 const enum interp_mode *interp = setup->stage.softpipe->interp;
596 GLuint slot, j;
597
598 /* use setup->vmin, vmax to point to vertices */
599 setup->vprovoke = prim->v[1];
600 setup->vmin = prim->v[0];
601 setup->vmax = prim->v[1];
602
603 setup->emaj.dx = setup->vmax->data[0][0] - setup->vmin->data[0][0];
604 setup->emaj.dy = setup->vmax->data[0][1] - setup->vmin->data[0][1];
605 /* NOTE: this is not really 1/area */
606 setup->oneoverarea = 1.0 / (setup->emaj.dx * setup->emaj.dx +
607 setup->emaj.dy * setup->emaj.dy);
608
609 /* z and w are done by linear interpolation:
610 */
611 line_linear_coeff(setup, 0, 2);
612 line_linear_coeff(setup, 0, 3);
613
614 /* setup interpolation for all the remaining attributes:
615 */
616 for (slot = 1; slot < setup->quad.nr_attrs; slot++) {
617 switch (interp[slot]) {
618 case INTERP_CONSTANT:
619 for (j = 0; j < NUM_CHANNELS; j++)
620 const_coeff(setup, slot, j);
621 break;
622
623 case INTERP_LINEAR:
624 for (j = 0; j < NUM_CHANNELS; j++)
625 line_linear_coeff(setup, slot, j);
626 break;
627
628 case INTERP_PERSPECTIVE:
629 for (j = 0; j < NUM_CHANNELS; j++)
630 line_persp_coeff(setup, slot, j);
631 break;
632 }
633 }
634 }
635
636
637 /**
638 * Plot a pixel in a line segment.
639 */
640 static INLINE void
641 plot(struct setup_stage *setup, GLint x, GLint y)
642 {
643 const GLint iy = y & 1;
644 const GLint ix = x & 1;
645 const GLint quadX = x - ix;
646 const GLint quadY = y - iy;
647 const GLint mask = (1 << ix) << (2 * iy);
648
649 if (quadX != setup->quad.x0 ||
650 quadY != setup->quad.y0)
651 {
652 /* flush prev quad, start new quad */
653
654 if (setup->quad.x0 != -1)
655 quad_shade(setup->stage.softpipe, &setup->quad);
656
657 setup->quad.x0 = quadX;
658 setup->quad.y0 = quadY;
659 setup->quad.mask = 0x0;
660 }
661
662 setup->quad.mask |= mask;
663 }
664
665
666
667 /**
668 * Do setup for line rasterization, then render the line.
669 * XXX single-pixel width, no stipple, etc
670 * XXX no scissoring yet.
671 */
672 static void
673 setup_line(struct prim_stage *stage, struct prim_header *prim)
674 {
675 const struct vertex_header *v0 = prim->v[0];
676 const struct vertex_header *v1 = prim->v[1];
677 struct setup_stage *setup = setup_stage( stage );
678
679 GLint x0 = (GLint) v0->data[0][0];
680 GLint x1 = (GLint) v1->data[0][0];
681 GLint y0 = (GLint) v0->data[0][1];
682 GLint y1 = (GLint) v1->data[0][1];
683 GLint dx = x1 - x0;
684 GLint dy = y1 - y0;
685 GLint xstep, ystep;
686
687 if (dx == 0 && dy == 0)
688 return;
689
690 setup_line_coefficients(setup, prim);
691
692 if (dx < 0) {
693 dx = -dx; /* make positive */
694 xstep = -1;
695 }
696 else {
697 xstep = 1;
698 }
699
700 if (dy < 0) {
701 dy = -dy; /* make positive */
702 ystep = -1;
703 }
704 else {
705 ystep = 1;
706 }
707
708 assert(dx >= 0);
709 assert(dy >= 0);
710
711 setup->quad.x0 = setup->quad.y0 = -1;
712 setup->quad.mask = 0x0;
713
714 if (dx > dy) {
715 /*** X-major line ***/
716 GLint i;
717 const GLint errorInc = dy + dy;
718 GLint error = errorInc - dx;
719 const GLint errorDec = error - dx;
720
721 for (i = 0; i < dx; i++) {
722 plot(setup, x0, y0);
723
724 x0 += xstep;
725 if (error < 0) {
726 error += errorInc;
727 }
728 else {
729 error += errorDec;
730 y0 += ystep;
731 }
732 }
733 }
734 else {
735 /*** Y-major line ***/
736 GLint i;
737 const GLint errorInc = dx + dx;
738 GLint error = errorInc - dy;
739 const GLint errorDec = error - dy;
740
741 for (i = 0; i < dy; i++) {
742 plot(setup, x0, y0);
743
744 y0 += ystep;
745
746 if (error < 0) {
747 error += errorInc;
748 }
749 else {
750 error += errorDec;
751 x0 += xstep;
752 }
753 }
754 }
755
756 /* draw final quad */
757 if (setup->quad.mask) {
758 quad_shade(setup->stage.softpipe, &setup->quad);
759 }
760 }
761
762
763 /**
764 * Do setup for point rasterization, then render the point.
765 * Round or square points...
766 * XXX could optimize a lot for 1-pixel points.
767 */
768 static void
769 setup_point(struct prim_stage *stage, struct prim_header *prim)
770 {
771 struct setup_stage *setup = setup_stage( stage );
772 GLfloat halfSize = 7.3; /*XXX this is a vertex attrib */
773 GLfloat halfSizeSquared = halfSize * halfSize;
774 const struct vertex_header *v0 = prim->v[0];
775 const GLfloat x = v0->data[FRAG_ATTRIB_WPOS][0];
776 const GLfloat y = v0->data[FRAG_ATTRIB_WPOS][1];
777 const GLint ixmin = block((GLint) (x - halfSize));
778 const GLint ixmax = block((GLint) (x + halfSize));
779 const GLint iymin = block((GLint) (y - halfSize));
780 const GLint iymax = block((GLint) (y + halfSize));
781 GLboolean round = GL_TRUE;
782 GLint ix, iy;
783 GLuint slot, j;
784
785 /* For points, all interpolants are constant-valued.
786 * However, for point sprites, we'll need to setup texcoords appropriately.
787 * XXX: which coefficients are the texcoords???
788 * We may do point sprites as textured quads...
789 *
790 * KW: We don't know which coefficients are texcoords - ultimately
791 * the choice of what interpolation mode to use for each attribute
792 * should be determined by the fragment program, using
793 * per-attribute declaration statements that include interpolation
794 * mode as a parameter. So either the fragment program will have
795 * to be adjusted for pointsprite vs normal point behaviour, or
796 * otherwise a special interpolation mode will have to be defined
797 * which matches the required behaviour for point sprites. But -
798 * the latter is not a feature of normal hardware, and as such
799 * probably should be ruled out on that basis.
800 */
801 setup->vprovoke = prim->v[0];
802 const_coeff(setup, 0, 2);
803 const_coeff(setup, 0, 3);
804 for (slot = 1; slot < setup->quad.nr_attrs; slot++) {
805 for (j = 0; j < NUM_CHANNELS; j++)
806 const_coeff(setup, slot, j);
807 }
808
809 /* XXX need to clip against scissor bounds too */
810
811 for (iy = iymin; iy <= iymax; iy += 2) {
812 for (ix = ixmin; ix <= ixmax; ix += 2) {
813
814 if (round) {
815 /* rounded points */
816 /* XXX for GL_SMOOTH, need to compute per-fragment coverage too */
817 GLfloat dx, dy;
818
819 setup->quad.mask = 0x0;
820
821 dx = (ix + 0.5) - x;
822 dy = (iy + 0.5) - y;
823 if (dx * dx + dy * dy <= halfSizeSquared)
824 setup->quad.mask |= MASK_BOTTOM_LEFT;
825
826 dx = (ix + 1.5) - x;
827 dy = (iy + 0.5) - y;
828 if (dx * dx + dy * dy <= halfSizeSquared)
829 setup->quad.mask |= MASK_BOTTOM_RIGHT;
830
831 dx = (ix + 0.5) - x;
832 dy = (iy + 1.5) - y;
833 if (dx * dx + dy * dy <= halfSizeSquared)
834 setup->quad.mask |= MASK_TOP_LEFT;
835
836 dx = (ix + 1.5) - x;
837 dy = (iy + 1.5) - y;
838 if (dx * dx + dy * dy <= halfSizeSquared)
839 setup->quad.mask |= MASK_TOP_RIGHT;
840 }
841 else {
842 /* square points */
843 setup->quad.mask = 0xf;
844
845 if (ix + 0.5 < x - halfSize)
846 setup->quad.mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
847
848 if (ix + 1.5 > x + halfSize)
849 setup->quad.mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
850
851 if (iy + 0.5 < y - halfSize)
852 setup->quad.mask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT);
853
854 if (iy + 1.5 > y + halfSize)
855 setup->quad.mask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
856 }
857
858 if (setup->quad.mask) {
859 setup->quad.x0 = ix;
860 setup->quad.y0 = iy;
861 quad_shade( setup->stage.softpipe, &setup->quad );
862 }
863 }
864 }
865 }
866
867
868
869 static void setup_end( struct prim_stage *stage )
870 {
871 }
872
873
874 struct prim_stage *prim_setup( struct softpipe_context *softpipe )
875 {
876 struct setup_stage *setup = CALLOC_STRUCT(setup_stage);
877
878 setup->stage.softpipe = softpipe;
879 setup->stage.begin = setup_begin;
880 setup->stage.point = setup_point;
881 setup->stage.line = setup_line;
882 setup->stage.tri = setup_tri;
883 setup->stage.end = setup_end;
884
885 setup->quad.coef = setup->coef;
886
887 return &setup->stage;
888 }