4 typedef struct clipsurf_s
6 struct clipsurf_s *next, *prev;
11 void (*callback)(void *nativedata, void *nativedata2);
14 float wstepx, wstepy, w00;
15 // wcurrent is a cached copy of w00 + wstepy * y,
16 // updated each time the surface is added to the stack,
17 // for quicker comparisons.
19 // this is a linked list of all edges belonging to this surface,
20 // used to remove them if this is a non-solid surface that is
21 // marked visible (it can not hide anything, so it is useless)
22 // struct clipedge_s *edgechain;
26 typedef struct clipedge_s
28 float x, realx, realxstep;
29 struct clipedge_s *next, *prev, *nextremove;
36 clipsurf_t *pavailsurf, *clipsurfs, *clipsurfsend;
37 clipedge_t *pavailedge, *clipedges, *clipedgesend, *newedges, **removeedges;
40 clipedge_t edgehead, edgetail;
41 clipedge_t maxedge = {2000000000.0f};
43 cvar_t r_clipwidth = {0, "r_clipwidth", "800"};
44 cvar_t r_clipheight = {0, "r_clipheight", "600"};
45 cvar_t r_clipedges = {CVAR_SAVE, "r_clipedges", "32768"};
46 cvar_t r_clipsurfaces = {CVAR_SAVE, "r_clipsurfaces", "8192"};
48 int clipwidth = 0, clipheight = 0;
49 int maxclipsurfs = 0, maxclipedges = 0;
50 int needededges, neededsurfs;
55 float w; // inverse depth (1/z)
59 clippixel_t *clipbuffer;
62 float r_clip_viewmatrix[3][3], r_clip_viewmulx, r_clip_viewmuly, r_clip_viewcenterx, r_clip_viewcentery;
64 //float xscale, yscale, xscaleinv, yscaleinv;
65 //float r_clip_nearclipdist, r_clip_nearclipdist2;
66 tinyplane_t r_clip_viewplane[5];
68 mempool_t *r_clip_mempool;
70 void R_Clip_MakeViewMatrix(void)
72 float pixelaspect, screenaspect, horizontalfieldofview, verticalfieldofview;
73 pixelaspect = (float) clipheight / (float) clipwidth * 320 / 240.0;
74 horizontalfieldofview = 2.0 * tan (r_refdef.fov_x/360*M_PI);
75 screenaspect = clipwidth * pixelaspect / clipheight;
76 verticalfieldofview = horizontalfieldofview / screenaspect;
77 r_clip_viewcenterx = clipwidth * 0.5 - 0.5;
78 r_clip_viewcentery = clipheight * 0.5 - 0.5;
79 r_clip_viewmulx = clipwidth / horizontalfieldofview;
80 r_clip_viewmuly = r_clip_viewmulx * pixelaspect;
81 // this constructs a transposed rotation matrix for the view (transposed matrices do the opposite of their normal behavior)
82 VectorCopy (vright, r_clip_viewmatrix[0]);
83 VectorNegate (vup, r_clip_viewmatrix[1]);
84 VectorCopy (vpn, r_clip_viewmatrix[2]);
85 // r_clip_nearclipdist = DotProduct(r_origin, vpn) + 4.0f;
86 // r_clip_nearclipdist2 = r_clip_nearclipdist - 8.0f;
87 VectorCopy (vpn, r_clip_viewplane[0].normal);
88 r_clip_viewplane[0].dist = DotProduct(r_origin, vpn);
89 memcpy(&r_clip_viewplane[1], &frustum[0], sizeof(tinyplane_t));
90 memcpy(&r_clip_viewplane[2], &frustum[1], sizeof(tinyplane_t));
91 memcpy(&r_clip_viewplane[3], &frustum[2], sizeof(tinyplane_t));
92 memcpy(&r_clip_viewplane[4], &frustum[3], sizeof(tinyplane_t));
94 // maxscreenscaleinv = (1.0f / max(clipwidth, clipheight)) * horizontalfieldofview * 0.5f;
95 // xscale = clipwidth / horizontalfieldofview;
96 // xscaleinv = 1.0 / xscale;
97 // yscale = xscale * pixelaspect;
98 // yscaleinv = 1.0 / yscale;
101 void R_Clip_StartFrame(void)
104 int newwidth, newheight, newmaxedges, newmaxsurfs;
105 newwidth = bound(80, r_clipwidth.integer, vid.realwidth * 2);
106 newheight = bound(60, r_clipheight.integer, vid.realheight * 2);
107 newmaxedges = bound(128, r_clipedges.integer, 262144);
108 newmaxsurfs = bound(32, r_clipsurfaces.integer, 65536);
109 if (newwidth != clipwidth || newheight != clipheight || maxclipedges != newmaxedges || maxclipsurfs != newmaxsurfs)
113 Mem_Free(clipbuffer);
122 Mem_Free(removeedges);
123 clipwidth = newwidth;
124 clipheight = newheight;
125 maxclipedges = newmaxedges;
126 maxclipsurfs = newmaxsurfs;
128 clipbuffer = Mem_Alloc(r_clip_mempool, clipwidth * clipheight * sizeof(clippixel_t));
130 clipedges = Mem_Alloc(r_clip_mempool, maxclipedges * sizeof(clipedge_t));
131 clipsurfs = Mem_Alloc(r_clip_mempool, maxclipsurfs * sizeof(clipsurf_t));
132 newedges = Mem_Alloc(r_clip_mempool, clipheight * sizeof(clipedge_t));
133 removeedges = Mem_Alloc(r_clip_mempool, clipheight * sizeof(clipedge_t *));
134 clipedgesend = clipedges + maxclipedges;
135 clipsurfsend = clipsurfs + maxclipsurfs;
138 memset(clipbuffer, 0, clipwidth * clipheight * sizeof(clippixel_t));
140 pavailedge = clipedges;
141 pavailsurf = clipsurfs;
142 // Clear the lists of edges to add and remove on each scan line.
146 for (i = 0;i < clipheight;i++)
148 newedges[i].next = &maxedge;
149 removeedges[i] = NULL;
152 R_Clip_MakeViewMatrix();
155 void ScanEdges (void);
157 void R_Clip_EndFrame(void)
160 if (maxclipedges < needededges)
162 Con_Printf("R_Clip: ran out of edges, increasing limit from %d to %d\n", maxclipedges, needededges);
163 Cvar_SetValue("r_clipedges", needededges);
165 if (maxclipsurfs < neededsurfs)
167 Con_Printf("R_Clip: ran out of surfaces, increasing limit from %d to %d\n", maxclipsurfs, neededsurfs);
168 Cvar_SetValue("r_clipsurfaces", neededsurfs);
172 void r_clip_start(void)
174 r_clip_mempool = Mem_AllocPool("R_Clip");
177 void r_clip_shutdown(void)
179 Mem_FreePool(&r_clip_mempool);
191 void r_clip_newmap(void)
195 void R_Clip_Init(void)
197 Cvar_RegisterVariable(&r_clipwidth);
198 Cvar_RegisterVariable(&r_clipheight);
199 Cvar_RegisterVariable(&r_clipedges);
200 Cvar_RegisterVariable(&r_clipsurfaces);
201 R_RegisterModule("R_Clip", r_clip_start, r_clip_shutdown, r_clip_newmap);
204 int R_Clip_TriangleToPlane(vec3_t point1, vec3_t point2, vec3_t point3, tinyplane_t *p)
208 VectorSubtract(point1, point2, v1);
209 VectorSubtract(point3, point2, v2);
210 CrossProduct(v1, v2, p->normal);
211 number = DotProduct(p->normal, p->normal);
214 *((int *)&y) = 0x5f3759df - ((* (int *) &number) >> 1);
215 y = y * (1.5f - (number * 0.5f * y * y));
216 VectorScale(p->normal, y, p->normal);
217 p->dist = DotProduct(point1, p->normal);
225 int R_Clip_TriangleToDoublePlane(double *point1, double *point2, double *point3, tinydoubleplane_t *p)
229 VectorSubtract(point1, point2, v1);
230 VectorSubtract(point3, point2, v2);
231 CrossProduct(v1, v2, p->normal);
232 number = DotProduct(p->normal, p->normal);
235 y = 1.0 / sqrt(number);
236 VectorScale(p->normal, y, p->normal);
237 p->dist = DotProduct(point1, p->normal);
245 int R_Clip_ClipPolygonToPlane(float *in, float *out, int inpoints, int stride, tinyplane_t *plane)
247 int i, outpoints, prevside, side;
248 float *prevpoint, prevdist, dist, dot;
250 // begin with the last point, then enter the loop with the first point as current
251 prevpoint = (float *) ((qbyte *)in + stride * (inpoints - 1));
252 prevdist = DotProduct(prevpoint, plane->normal) - plane->dist;
253 prevside = prevdist >= 0 ? SIDE_FRONT : SIDE_BACK;
257 for (;i < inpoints;i++)
262 (qbyte *)in += stride;
265 dist = DotProduct(in, plane->normal) - plane->dist;
266 side = dist >= 0 ? SIDE_FRONT : SIDE_BACK;
268 if (prevside == SIDE_FRONT)
270 VectorCopy(prevpoint, out);
273 if (side == SIDE_FRONT)
276 else if (side == SIDE_BACK)
279 // generate a split point
280 dot = prevdist / (prevdist - dist);
281 out[0] = prevpoint[0] + dot * (in[0] - prevpoint[0]);
282 out[1] = prevpoint[1] + dot * (in[1] - prevpoint[1]);
283 out[2] = prevpoint[2] + dot * (in[2] - prevpoint[2]);
291 float tempverts[256][3];
292 float tempverts2[256][3];
293 float screenverts[256][3];
295 // LordHavoc: this code is based primarily on the ddjzsort code
297 // Clips polygon to view frustum and nearclip, transforms polygon to viewspace, perspective projects polygon to screenspace,
298 // and adds polygon's edges to the global edge table.
299 void R_Clip_AddPolygon (vec_t *points, int numverts, int stride, int solid, void (*callback)(void *nativedata, void *nativedata2), void *nativedata, void *nativedata2, tinyplane_t *polyplane)
301 float deltax, deltay, vx, vy, vz, fx;
302 int i, j, k, nextvert, temp, topy, bottomy, height, addededges;
304 // tinydoubleplane_t plane;
305 tinyplane_t localplane;
306 // tinyplane_t testplane;
312 if (polyplane == NULL)
314 polyplane = &localplane;
315 // calculate the plane for the polygon
316 if (!R_Clip_TriangleToPlane((float *) points, (float *) ((qbyte *)points + stride), (float *) ((qbyte *)points + 2 * stride), polyplane))
318 for (i = 0;i < numverts;i++)
319 for (j = i + 1;j < numverts;j++)
320 for (k = j + 1;k < numverts;k++)
321 if (R_Clip_TriangleToPlane((float *) ((qbyte *)points + i * stride), (float *) ((qbyte *)points + j * stride), (float *) ((qbyte *)points + k * stride), polyplane))
327 // caller hasn't checked if this polygon faces the view, so we have to check
328 if (DotProduct(r_origin, polyplane->normal) < (polyplane->dist + 0.5f))
331 #if 0 // debugging (validates planes passed in)
334 // calculate the plane for the polygon
335 if (!R_Clip_TriangleToPlane((float *) points, (float *) ((qbyte *)points + stride), (float *) ((qbyte *)points + 2 * stride), &localplane))
337 for (i = 0;i < numverts;i++)
338 for (j = i + 1;j < numverts;j++)
339 for (k = j + 1;k < numverts;k++)
340 if (R_Clip_TriangleToPlane((float *) ((qbyte *)points + i * stride), (float *) ((qbyte *)points + j * stride), (float *) ((qbyte *)points + k * stride), &localplane))
346 // if ((DotProduct(r_origin, polyplane->normal) < (polyplane->dist + 0.5f)) != (DotProduct(r_origin, localplane.normal) < (localplane.dist + 0.5f)))
347 if (DotProduct(polyplane->normal, localplane.normal) < 0.9f)
355 // for adaptive limits
356 needededges += numverts;
359 if (pavailsurf >= clipsurfsend)
362 // clip to view frustum and nearclip
363 if (numverts < 3) return;numverts = R_Clip_ClipPolygonToPlane(points , tempverts2[0], numverts, stride, &r_clip_viewplane[0]);
364 if (numverts < 3) return;numverts = R_Clip_ClipPolygonToPlane(tempverts2[0], tempverts[0], numverts, sizeof(float) * 3, &r_clip_viewplane[1]);
365 if (numverts < 3) return;numverts = R_Clip_ClipPolygonToPlane(tempverts[0], tempverts2[0], numverts, sizeof(float) * 3, &r_clip_viewplane[2]);
366 if (numverts < 3) return;numverts = R_Clip_ClipPolygonToPlane(tempverts2[0], tempverts[0], numverts, sizeof(float) * 3, &r_clip_viewplane[3]);
367 if (numverts < 3) return;numverts = R_Clip_ClipPolygonToPlane(tempverts[0], tempverts2[0], numverts, sizeof(float) * 3, &r_clip_viewplane[4]);
371 Sys_Error("R_Clip_AddPolygon: polygon exceeded 256 vertex buffer\n");
373 // it survived the clipping, transform to viewspace and project to screenspace
375 if (pavailedge + numverts > clipedgesend)
379 for (i = 0;i < numverts;i++)
381 vx = tempverts2[i][0] - r_origin[0];
382 vy = tempverts2[i][1] - r_origin[1];
383 vz = tempverts2[i][2] - r_origin[2];
384 screenverts[i][2] = 1.0f / (r_clip_viewmatrix[2][0] * vx + r_clip_viewmatrix[2][1] * vy + r_clip_viewmatrix[2][2] * vz);
385 screenverts[i][0] = (r_clip_viewmatrix[0][0] * vx + r_clip_viewmatrix[0][1] * vy + r_clip_viewmatrix[0][2] * vz) * r_clip_viewmulx * screenverts[i][2] + r_clip_viewcenterx;
386 screenverts[i][1] = (r_clip_viewmatrix[1][0] * vx + r_clip_viewmatrix[1][1] * vy + r_clip_viewmatrix[1][2] * vz) * r_clip_viewmuly * screenverts[i][2] + r_clip_viewcentery;
390 if (polyplane != NULL)
394 distinv = 1.0f / (polyplane->dist - DotProduct(r_origin, polyplane->normal));
395 pavailsurf->wstepx = DotProduct(r_clip_viewmatrix[0], polyplane->normal) * xscaleinv * distinv;
396 pavailsurf->wstepy = DotProduct(r_clip_viewmatrix[1], polyplane->normal) * yscaleinv * distinv;
397 pavailsurf->w00 = DotProduct(r_clip_viewmatrix[2], polyplane->normal) * distinv - r_clip_viewcenterx * pavailsurf->wstepx - r_clip_viewcentery * pavailsurf->wstepy;
404 // calculate the plane for the polygon
405 if (!R_Clip_TriangleToPlane(screenverts[0], screenverts[1], screenverts[2], &localplane))
407 for (i = 0;i < numverts;i++)
408 for (j = i + 1;j < numverts;j++)
409 for (k = j + 1;k < numverts;k++)
410 if (R_Clip_TriangleToPlane(screenverts[i], screenverts[j], screenverts[k], &localplane))
416 // Set up the 1/z gradients from the polygon, calculating the
417 // base value at screen coordinate 0,0 so we can use screen
418 // coordinates directly when calculating 1/z from the gradients
419 distinv = 1.0f / localplane.normal[2];
420 pavailsurf->wstepx = -(localplane.normal[0] * distinv);
421 pavailsurf->wstepy = -(localplane.normal[1] * distinv);
422 pavailsurf->w00 = localplane.dist * distinv;
428 prevdist = z1 * plane.normal[2] - plane.dist;
429 dist = z2 * plane.normal[2] - plane.dist;
430 d = prevdist / (prevdist - dist);
431 zc = z1 + d * (z2 - z1);
433 prevdist = plane.normal[0] + z1 * plane.normal[2] - plane.dist;
434 dist = plane.normal[0] + z2 * plane.normal[2] - plane.dist;
435 d = prevdist / (prevdist - dist);
436 zx = (z1 + d * (z2 - z1)) - zc;
438 prevdist = plane.normal[1] + z1 * plane.normal[2] - plane.dist;
439 dist = plane.normal[1] + z2 * plane.normal[2] - plane.dist;
440 d = prevdist / (prevdist - dist);
441 zy = (z1 + d * (z2 - z1)) - zc;
445 zc = (-plane.dist) / ((-plane.dist) - (plane.normal[2] - plane.dist));
446 zx = ((plane.normal[0] - plane.dist) / ((plane.normal[0] - plane.dist) - (plane.normal[0] + plane.normal[2] - plane.dist))) - zc;
447 zy = ((plane.normal[1] - plane.dist) / ((plane.normal[1] - plane.dist) - (plane.normal[1] + plane.normal[2] - plane.dist))) - zc;
450 // zc = (plane.dist / plane.normal[2]);
451 // zx = -(plane.normal[0] / plane.normal[2]);
452 // zy = -(plane.normal[1] / plane.normal[2]);
453 // zy = ((plane.normal[1] - plane.dist) / (-plane.normal[2])) + ((plane.dist) / (-plane.normal[2]));
455 for (i = 0;i < numverts;i++)
457 vx = tempverts2[i][0] - r_origin[0];
458 vy = tempverts2[i][1] - r_origin[1];
459 vz = tempverts2[i][2] - r_origin[2];
460 screenverts[i][0] = r_clip_viewmatrix[0][0] * vx + r_clip_viewmatrix[0][1] * vy + r_clip_viewmatrix[0][2] * vz;
461 screenverts[i][1] = r_clip_viewmatrix[1][0] * vx + r_clip_viewmatrix[1][1] * vy + r_clip_viewmatrix[1][2] * vz;
462 screenverts[i][2] = r_clip_viewmatrix[2][0] * vx + r_clip_viewmatrix[2][1] * vy + r_clip_viewmatrix[2][2] * vz;
466 // calculate the plane for the polygon
467 for (i = 0;i < numverts;i++)
468 for (j = i + 1;j < numverts;j++)
469 for (k = j + 1;k < numverts;k++)
470 if (R_Clip_TriangleToDoublePlane(screenverts[i], screenverts[j], screenverts[k], &plane))
475 distinv = 1.0f / plane.dist;
476 pavailsurf->d_zistepx = plane.normal[0] * xscaleinv * distinv;
477 pavailsurf->d_zistepy = -plane.normal[1] * yscaleinv * distinv;
478 pavailsurf->d_ziorigin = plane.normal[2] * distinv - r_clip_viewcenterx * pavailsurf->wstepx - r_clip_viewcentery * pavailsurf->wstepy;
480 for (i = 0;i < numverts;i++)
482 screenverts[i][2] = 1.0f / (screenverts[i][2]);
483 screenverts[i][0] = screenverts[i][0] * r_clip_viewmulx * screenverts[i][2] + r_clip_viewcenterx;
484 screenverts[i][1] = screenverts[i][1] * r_clip_viewmuly * screenverts[i][2] + r_clip_viewcentery;
486 // if (screenverts[i][0] < -0.5)
487 // screenverts[i][0] = -0.5;
488 // if (screenverts[i][0] > (clipwidth - 0.5))
489 // screenverts[i][0] = clipwidth - 0.5;
490 // if (screenverts[i][1] < -0.5)
491 // screenverts[i][1] = -0.5;
492 // if (screenverts[i][1] > (clipheight - 0.5))
493 // screenverts[i][1] = clipheight - 0.5;
494 // if (screenverts[i][2] <= 0.0)
495 // Con_Printf("R_Clip_AddPolygon: vertex z <= 0!\n");
501 // Add each edge in turn
502 for (i = 0;i < numverts;i++)
505 if (nextvert >= numverts)
508 topy = (int)ceil(screenverts[i][1]);
509 bottomy = (int)ceil(screenverts[nextvert][1]);
510 height = bottomy - topy;
512 continue; // doesn't cross any scan lines
521 if (bottomy > clipheight)
522 bottomy = clipheight;
526 pavailedge->leading = 1;
528 deltax = screenverts[i][0] - screenverts[nextvert][0];
529 deltay = screenverts[i][1] - screenverts[nextvert][1];
531 pavailedge->realxstep = deltax / deltay;
532 pavailedge->realx = screenverts[nextvert][0] + ((float)topy - screenverts[nextvert][1]) * pavailedge->realxstep;
539 if (bottomy > clipheight)
540 bottomy = clipheight;
544 pavailedge->leading = 0;
546 deltax = screenverts[nextvert][0] - screenverts[i][0];
547 deltay = screenverts[nextvert][1] - screenverts[i][1];
549 pavailedge->realxstep = deltax / deltay;
550 pavailedge->realx = screenverts[i][0] + ((float)topy - screenverts[i][1]) * pavailedge->realxstep;
553 // Put the edge on the list to be added on top scan
554 fx = pavailedge->x = bound(0.0f, pavailedge->realx, clipwidth - 0.5f);
555 pedge = &newedges[topy];
556 while (fx > pedge->next->x)
558 pavailedge->next = pedge->next;
559 pedge->next = pavailedge;
561 // Put the edge on the list to be removed after final scan
562 pavailedge->nextremove = removeedges[bottomy - 1];
563 removeedges[bottomy - 1] = pavailedge;
565 // Associate the edge with the surface
566 pavailedge->psurf = pavailsurf;
576 // Create the surface, so we'll know how to sort and draw from the edges
577 pavailsurf->next = NULL;
578 pavailsurf->prev = NULL;
579 pavailsurf->state = 0;
580 pavailsurf->visible = false;
581 pavailsurf->callback = callback;
582 pavailsurf->nativedata = nativedata;
583 pavailsurf->nativedata2 = nativedata2;
584 pavailsurf->solid = solid;
585 pavailsurf->removed = false;
589 /////////////////////////////////////////////////////////////////////
590 // Scan all the edges in the global edge table into spans.
591 /////////////////////////////////////////////////////////////////////
592 void ScanEdges (void)
595 float fx, fy, w, w2, clipwidthf = clipwidth - 0.5f;
596 clipedge_t *pedge, *pedge2, *ptemp;
597 clipsurf_t *psurf, *psurf2;
605 // Set up the active edge list as initially empty, containing
606 // only the sentinels (which are also the background fill). Most
607 // of these fields could be set up just once at start-up
608 edgehead.next = &edgetail;
609 edgehead.prev = NULL;
610 edgehead.x = edgehead.realx = -0.9999f; // left edge of screen
611 edgehead.realxstep = 0;
612 edgehead.leading = 1;
613 edgehead.psurf = &surfstack;
615 edgetail.next = NULL; // mark end of list
616 edgetail.prev = &edgehead;
617 edgetail.x = edgetail.realx = clipwidth + 0.5f; // right edge of screen
618 edgetail.realxstep = 0;
619 edgetail.leading = 0;
620 edgetail.psurf = &surfstack;
622 // The background surface is the entire stack initially, and
623 // is infinitely far away, so everything sorts in front of it.
624 // This could be set just once at start-up
625 surfstack.solid = true;
626 surfstack.visible = true; // no callback
627 surfstack.next = surfstack.prev = &surfstack;
628 surfstack.wcurrent = surfstack.w00 = -999999.0;
629 surfstack.wstepx = surfstack.wstepy = 0.0;
630 surfstack.removed = false;
632 // rescan causes the edges to be compared at the span level
633 // it is false if the scanline will be identical to the previous
635 for (y = 0;y < clipheight;y++)
639 cb = clipbuffer + y * clipwidth;
642 // Sort in any edges that start on this scan
643 if (newedges[y].next != &maxedge)
646 pedge = newedges[y].next;
648 while (pedge != &maxedge)
650 if (pedge->psurf->removed)
656 while (pedge->x > pedge2->next->x)
657 pedge2 = pedge2->next;
660 pedge->next = pedge2->next;
661 pedge->prev = pedge2;
662 pedge2->next->prev = pedge;
663 pedge2->next = pedge;
670 // Scan out the active edges into spans
672 // Start out with the left background edge already inserted, and the surface stack containing only the background
676 // must always rescan if rendering to wbuffer
681 for (pedge = edgehead.next;pedge;pedge = pedge->next)
684 psurf = pedge->psurf;
687 pedge2 = pedge->next;
688 pedge->prev->next = pedge->next;
689 pedge->next->prev = pedge->prev;
690 pedge->next = pedge->prev = pedge;
700 // It's a leading edge. Figure out where it is
701 // relative to the current surfaces and insert in
702 // the surface stack; if it's on top, emit the span
703 // for the current top.
704 // First, make sure the edges don't cross
705 if (++psurf->state == 1)
708 // Calculate the surface's 1/z value at this pixel, and cache the y depth for quick compares later
709 w = (psurf->wcurrent = psurf->w00 + psurf->wstepy * fy) + psurf->wstepx * fx;
713 // See if that makes it a new top surface
714 psurf2 = surfstack.next;
715 w2 = psurf2->wcurrent + psurf2->wstepx * fx;
716 // if (w2 < 0 && psurf2 != &surfstack)
721 // It's a new top surface
722 // emit the span for the current top
723 if (fx > cx && !psurf2->visible)
725 psurf2->visible = true;
726 psurf2->callback(psurf2->nativedata, psurf2->nativedata2);
730 for (x = ceil(cx), x2 = ceil(fx) >= clipwidth ? clipwidth : ceil(fx), zi = psurf2->wcurrent + psurf2->wstepx * x;x < x2;x++, zi += psurf2->wstepx)
736 // Add the edge to the stack
737 psurf->next = psurf2;
738 psurf2->prev = psurf;
739 surfstack.next = psurf;
740 psurf->prev = &surfstack;
744 // Not a new top; sort into the surface stack.
745 // Guaranteed to terminate due to sentinel background surface
748 psurf2 = psurf2->next;
749 w2 = psurf2->wcurrent + psurf2->wstepx * fx;
750 // if (w2 < 0 && psurf2 != &surfstack)
755 // Insert the surface into the stack
756 psurf->next = psurf2;
757 psurf->prev = psurf2->prev;
758 psurf2->prev->next = psurf;
759 psurf2->prev = psurf;
765 // It's a trailing edge; if this was the top surface,
766 // emit the span and remove it.
767 // First, make sure the edges didn't cross
768 if (--psurf->state == 0)
770 if (surfstack.next == psurf)
774 // It's on top, emit the span
775 if (fx > cx && !psurf->visible)
777 psurf->visible = true;
778 psurf->callback(psurf->nativedata, psurf->nativedata2);
783 for (x = ceil(cx), x2 = ceil(fx) >= clipwidth ? clipwidth : ceil(fx), zi = psurf->w00 + psurf->wstepx * x + psurf->wstepy * fy;x < x2;x++, zi += psurf->wstepx)
790 // Remove the surface from the stack
791 psurf->next->prev = psurf->prev;
792 psurf->prev->next = psurf->next;
796 // mark and remove all non-solid surfaces that are ontop
797 while (!surfstack.next->solid)
799 psurf = surfstack.next;
802 psurf->visible = true;
803 psurf->callback(psurf->nativedata, psurf->nativedata2);
805 psurf->removed = true;
806 psurf->next->prev = psurf->prev;
807 psurf->prev->next = psurf->next;
808 // isolate the surface
809 psurf->next = psurf->prev = psurf;
815 // Remove edges that are done
816 pedge = removeedges[y];
821 if (!pedge->psurf->removed)
823 pedge->prev->next = pedge->next;
824 pedge->next->prev = pedge->prev;
825 if (pedge->psurf->visible)
828 pedge = pedge->nextremove;
832 // Step the remaining edges one scan line, and re-sort
833 for (pedge = edgehead.next;pedge != &edgetail;)
836 if (pedge->psurf->removed)
838 pedge->next->prev = pedge->prev;
839 pedge->prev->next = pedge->next;
840 pedge->next = pedge->prev = pedge;
846 if (pedge->realxstep)
848 pedge->realx += pedge->realxstep;
849 pedge->x = bound(0.0f, pedge->realx, clipwidthf);
853 // Move the edge back to the proper sorted location, if necessary
854 while (fx < pedge->prev->x)
856 if (!rescan && (pedge->psurf->solid || pedge->prev->psurf->solid))
858 pedge2 = pedge->prev;
859 pedge2->next = pedge->next;
860 pedge->next->prev = pedge2;
861 pedge2->prev->next = pedge;
862 pedge->prev = pedge2->prev;
863 pedge->next = pedge2;
864 pedge2->prev = pedge;
872 void R_Clip_DisplayBuffer(void)
877 static int firstupload = true;
878 qbyte clipbuffertex[256*256], *b;
879 if (!r_render.integer)
881 if (clipwidth > 256 || clipheight > 256)
883 glBlendFunc(GL_ONE, GL_ONE);
884 glBindTexture(GL_TEXTURE_2D, 8000);
887 memset(clipbuffertex, 0, sizeof(clipbuffertex));
888 glTexImage2D(GL_TEXTURE_2D, 0, 1, 256, 256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, clipbuffertex);
890 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
891 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
892 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
894 glColor4ub(0.5, 0.5, 0.5);
899 for (i = 0;i < clipwidth*clipheight;i++)
901 if (clipbuffer[i].w > 0)
902 *b++ = bound(0, (int) (clipbuffer[i].w * 4096.0f), 255);
906 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, clipwidth, clipheight, GL_LUMINANCE, GL_UNSIGNED_BYTE, clipbuffertex);
908 glTexCoord2f (0 , 0 );glVertex2f (0 , 0 );
909 glTexCoord2f (clipwidth / 256.0f, 0 );glVertex2f (vid.conwidth, 0 );
910 glTexCoord2f (clipwidth / 256.0f, clipheight / 256.0f);glVertex2f (vid.conwidth, vid.conheight);
911 glTexCoord2f (0 , clipheight / 256.0f);glVertex2f (0 , vid.conheight);
913 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
914 // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
915 // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
920 float boxpoints[4*3];
922 #define R_Clip_MinsBoxPolygon(axis, axisvalue, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, callback, nativedata, nativedata2, plane) \
924 if (r_origin[(axis)] < ((axisvalue) - 0.5f))\
926 (plane)->dist = -axisvalue;\
927 boxpoints[ 0] = x1;boxpoints[ 1] = y1;boxpoints[ 2] = z1;\
928 boxpoints[ 3] = x2;boxpoints[ 4] = y2;boxpoints[ 5] = z2;\
929 boxpoints[ 6] = x3;boxpoints[ 7] = y3;boxpoints[ 8] = z3;\
930 boxpoints[ 9] = x4;boxpoints[10] = y4;boxpoints[11] = z4;\
931 R_Clip_AddPolygon (boxpoints, 4, sizeof(float[3]), false, callback, nativedata, nativedata2, plane);\
935 #define R_Clip_MaxsBoxPolygon(axis, axisvalue, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, callback, nativedata, nativedata2, plane) \
937 if (r_origin[(axis)] > ((axisvalue) + 0.5f))\
939 (plane)->dist = axisvalue;\
940 boxpoints[ 0] = x1;boxpoints[ 1] = y1;boxpoints[ 2] = z1;\
941 boxpoints[ 3] = x2;boxpoints[ 4] = y2;boxpoints[ 5] = z2;\
942 boxpoints[ 6] = x3;boxpoints[ 7] = y3;boxpoints[ 8] = z3;\
943 boxpoints[ 9] = x4;boxpoints[10] = y4;boxpoints[11] = z4;\
944 R_Clip_AddPolygon (boxpoints, 4, sizeof(float[3]), false, callback, nativedata, nativedata2, plane);\
948 tinyplane_t clipboxplane[6] =
958 void R_Clip_AddBox(float *a, float *b, void (*callback)(void *nativedata, void *nativedata2), void *nativedata, void *nativedata2)
960 if (r_origin[0] >= (a[0] - 5.0f) && r_origin[0] < (b[0] + 5.0f)
961 && r_origin[1] >= (a[1] - 5.0f) && r_origin[1] < (b[1] + 5.0f)
962 && r_origin[2] >= (a[2] - 5.0f) && r_origin[2] < (b[2] + 5.0f))
964 callback(nativedata, nativedata2);
971 R_Clip_MinsBoxPolygon
978 callback, nativedata, nativedata2, &clipboxplane[0]
980 R_Clip_MaxsBoxPolygon
987 callback, nativedata, nativedata2, &clipboxplane[1]
989 R_Clip_MinsBoxPolygon
996 callback, nativedata, nativedata2, &clipboxplane[2]
998 R_Clip_MaxsBoxPolygon
1005 callback, nativedata, nativedata2, &clipboxplane[3]
1007 R_Clip_MinsBoxPolygon
1014 callback, nativedata, nativedata2, &clipboxplane[4]
1016 R_Clip_MaxsBoxPolygon
1023 callback, nativedata, nativedata2, &clipboxplane[5]