Search
lxdream.org :: lxdream/src/pvr2/rendbkg.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/rendbkg.c
changeset 649:620c5c6496b5
prev645:a7392098299c
author nkeynes
date Tue Mar 11 08:50:16 2008 +0000 (16 years ago)
branchlxdream-render
permissions -rw-r--r--
last change Use maxz rather than minz for tri sorting (better results atm)
Change depth-test-disable to depth-mask (more correct)
Implement alpha test for punchthru polys
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * PVR2 background renderer. 
     5  *
     6  * Yes, it uses the same basic data structure. Yes, it needs to be handled
     7  * completely differently.
     8  *
     9  * PVR2 backgrounds are defined as a set of three fully specified vertexes,
    10  * stored in compiled-vertex format. The vertexes form a triangle which is
    11  * rendered in the normal fashion. Points outside the triangle are rendered
    12  * by extrapolating from the gradients established by the triangle, giving
    13  * an overall smooth gradient across the background. Points are colour-clamped
    14  * prior to output to the buffer.
    15  *
    16  * As a special case, if all three points lie on the same line (or are the same
    17  * point, the third point is used by itself to define the entire buffer (ie
    18  * effectively a solid colour).
    19  *
    20  * Note: this would be really simple if GL did unclamped colour interpolation
    21  * but it doesn't (portably), which makes this roughly 2 orders of magnitude
    22  * more complicated than it otherwise would be.
    23  *
    24  * Copyright (c) 2005 Nathan Keynes.
    25  *
    26  * This program is free software; you can redistribute it and/or modify
    27  * it under the terms of the GNU General Public License as published by
    28  * the Free Software Foundation; either version 2 of the License, or
    29  * (at your option) any later version.
    30  *
    31  * This program is distributed in the hope that it will be useful,
    32  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    33  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    34  * GNU General Public License for more details.
    35  */
    37 #include <sys/time.h>
    38 #include "display.h"
    39 #include "pvr2/pvr2.h"
    40 #include <math.h>
    42 #define MAX_CLAMP_LINES 8
    43 #define MAX_VERTEXES 256
    44 #define MAX_REGIONS  256
    46 #define FARGB_A(x) (((float)(((x)>>24)+1))/256.0)
    47 #define FARGB_R(x) (((float)((((x)>>16)&0xFF)+1))/256.0)
    48 #define FARGB_G(x) (((float)((((x)>>8)&0xFF)+1))/256.0)
    49 #define FARGB_B(x) (((float)(((x)&0xFF)+1))/256.0)
    51 /**
    52  * Convert a half-float (16-bit) FP number to a regular 32-bit float.
    53  * Source is 1-bit sign, 5-bit exponent, 10-bit mantissa.
    54  * TODO: Check the correctness of this.
    55  */
    56 static float halftofloat( uint16_t half )
    57 {
    58     union {
    59         float f;
    60         uint32_t i;
    61     } temp;
    62     /* int e = ((half & 0x7C00) >> 10) - 15 + 127;
    64     temp.i = ((half & 0x8000) << 16) | (e << 23) |
    65     ((half & 0x03FF) << 13); */
    66     temp.i = ((uint32_t)half)<<16;
    67     return temp.f;
    68 }
    70 void render_unpack_vertexes( struct vertex_unpacked *out, uint32_t poly1, 
    71 			     uint32_t *vertexes, int num_vertexes,
    72 			     int vertex_size, int render_mode )
    73 {
    74     int m = 0, i;
    75     if( render_mode == RENDER_FULLMOD ) {
    76 	m = (vertex_size - 3)/2;
    77     }
    79     for( i=0; i<num_vertexes; i++ ) {
    80 	float *vertexf = (float *)vertexes;
    81 	int k = m + 3;
    82 	out[i].x = vertexf[0];
    83 	out[i].y = vertexf[1];
    84 	out[i].z = vertexf[2];
    85     	if( POLY1_TEXTURED(poly1) ) {
    86 	    if( POLY1_UV16(poly1) ) {
    87 		out[i].u = halftofloat(vertexes[k]>>16);
    88 		out[i].v = halftofloat(vertexes[k]);
    89 		k++;
    90 	    } else {
    91 		out[i].u = vertexf[k];
    92 		out[i].v = vertexf[k+1];
    93 		k+=2;
    94 	    }
    95 	} else {
    96 	    out[i].u = 0;
    97 	    out[i].v = 0;
    98 	}
    99 	uint32_t argb = vertexes[k++];
   100 	out[i].rgba[0] = FARGB_R(argb);
   101 	out[i].rgba[1] = FARGB_G(argb);
   102         out[i].rgba[2] = FARGB_B(argb);
   103 	out[i].rgba[3] = FARGB_A(argb);
   104 	if( POLY1_SPECULAR(poly1) ) {
   105 	    uint32_t offset = vertexes[k++];
   106 	    out[i].offset_rgba[0] = FARGB_R(offset);
   107 	    out[i].offset_rgba[1] = FARGB_G(offset);
   108 	    out[i].offset_rgba[2] = FARGB_B(offset);
   109 	    out[i].offset_rgba[3] = FARGB_A(offset);
   110 	}
   111 	vertexes += vertex_size;
   112     }
   113 }
   115 /**
   116  * Compute the line where k = target_k, (where k is normally one of
   117  * r,g,b,a, or z) and determines the points at which the line intersects
   118  * the viewport (0,0,width,height).
   119  *
   120  * @param center_x the x value for the center position
   121  * @param center_y the y value for the center position
   122  * @param center_k the k value for the center position
   123  * @param width Width of the viewport (ie 640)
   124  * @param height Height of the viewport (ie 480)
   125  * @param target_k determine the line where k = this value, ie 1.0
   126  * @param detxy
   127  * @param target Array to write the resultant x,y pairs to (note this
   128  * function only sets x and y values).
   129  * @return number of vertexes written to the target.
   130  */
   131 static int compute_colour_line( float center_x, float center_y, float center_k, 
   132 		  int width, int height, float target_k,
   133 		  float detxy, float detxk, float detyk,
   134 		  struct vertex_unpacked *target ) {
   135     int num_points = 0;
   136     float tmpk = (target_k - center_k) * detxy;
   137     float x0 = -1;
   138     float x1 = -1;
   140     if( detyk != 0 ) {
   141 	x0 = (tmpk - ((0-center_y)*detxk))/detyk + center_x; /* x where y=0 */
   142 	if( x0 >= 0.0 && x0 <= width ) {
   143 	    target[num_points].x = x0;
   144 	    target[num_points].y = 0.0;
   145 	    num_points++;
   146 	}
   148 	x1 = (tmpk - ((height-center_y)*detxk))/detyk + center_x; /* x where y=height */
   149 	if( x1 >= 0.0 && x1 <= width ) {
   150 	    target[num_points].x = x1;
   151 	    target[num_points].y = height;
   152 	    num_points++;
   153 	}
   154     }
   156     if( detxk != 0 ) {
   157 	if( x0 != 0.0 && x1 != 0.0 ) { /* If x0 == 0 or x1 == 0, then we already have this one */
   158 	    float y0 = (tmpk - ((0-center_x)*detyk))/detxk + center_y; /* y where x=0 */
   159 	    if( y0 >= 0.0 && y0 <= height ) {
   160 		target[num_points].x = 0.0;
   161 		target[num_points].y = y0;
   162 		num_points++;
   163 	    }
   164 	}
   166 	if( x0 != width && x1 != width ) {
   167 	    float y1 = (tmpk - ((width-center_x)*detyk))/detxk + center_y; /* y where x=width */
   168 	    if( y1 >= 0.0 && y1 <= height ) {
   169 		target[num_points].x = width;
   170 		target[num_points].y = y1;
   171 		num_points++;
   172 	    }
   173 	}
   174     }
   176     if( num_points == 0 || num_points == 2 ) {
   177 	/* 0 = no points - line doesn't pass through the viewport */
   178 	/* 2 = normal case - got 2 endpoints */
   179 	return num_points;
   180     } else {
   181 	ERROR( "compute_colour_line got bad number of points: %d", num_points );
   182 	return 0;
   183     }
   184 }
   186 /**
   187  * A region describes a portion of the screen, possibly subdivided by a line.
   188  * if region_left and region_right are -1, this is a terminal region that can
   189  * be rendered directly. Otherwise region_left and region_right refer two 
   190  * sub-regions that are separated by the line segment vertex1-vertex2.
   191  */
   192 struct bkg_region {
   193     /* Vertexes marking the line segment that splits this region */
   194     int vertex1;
   195     int vertex2;
   196     /* Index of the left sub-region */
   197     int region_left;
   198     /* Index of the right sub-region */
   199     int region_right;
   200 };
   202 /**
   203  * Convenience structure to bundle together the vertex and region data.
   204  */
   205 struct bkg_scene {
   206     int num_vertexes;
   207     int num_regions;
   208     struct vertex_unpacked vertexes[MAX_VERTEXES];
   209     struct bkg_region regions[MAX_REGIONS];
   210 };
   212 /**
   213  * Constants returned by compute_line_intersection. Note that for these purposes,
   214  * "Left" means the point(s) result in a negative value in the line equation, while
   215  * "Right" means the points(s) result in a positive value in the line equation. The
   216  * exact meaning isn't particularly important though, as long as we're consistent
   217  * throughout this process
   218  */
   219 #define LINE_COLLINEAR 0   /* The line segments are part of the same line */
   220 #define LINE_SIDE_LEFT 1   /* The second line is entirely to the "left" of the first line */
   221 #define LINE_SIDE_RIGHT 2  /* The second line is entirely to the "right" of the first line */
   222 #define LINE_INTERSECT_FROM_LEFT 3 /* The lines intersect, and (x3,y3) is to the "left" of the first line */
   223 #define LINE_INTERSECT_FROM_RIGHT 4 /* The lines intersect, and (x3,y3) is to the "right" of the first line */
   224 #define LINE_SKEW 5        /* The line segments neither intersect nor do any of the above apply (should never happen here) */
   226 /**
   227  * Compute the intersection of two line segments, where 
   228  * (x1,y1)-(x2,y2) defines the target segment, and
   229  * (x3,y3)-(x4,y4) defines the line intersecting it.
   230  *
   231  * Based off work by Mukesh Prasad (http://www.acm.org/pubs/tog/GraphicsGems/index.html)
   232  *
   233  * @return one of the above LINE_* constants
   234  */
   235 static int compute_line_intersection( float x1, float y1,   /* First line segment */
   236 				      float x2, float y2,
   237 				      float x3, float y3,   /* Second line segment */
   238 				      float x4, float y4,
   239 				      float *x, float *y  )  /* Output value: */
   240 {
   241     float a1, a2, b1, b2, c1, c2; /* Coefficients of line eqns. */
   242     float r1, r2, r3, r4;         /* test values */
   243     float denom;     /* Intermediate values */
   245     /* Compute a1, b1, c1, where line joining points 1 and 2
   246      * is "a1 x  +  b1 y  +  c1  =  0".
   247      */
   249     a1 = y2 - y1;
   250     b1 = x1 - x2;
   251     c1 = x2 * y1 - x1 * y2;
   253     /* Compute r3 and r4. */
   255     r3 = a1 * x3 + b1 * y3 + c1;
   256     r4 = a1 * x4 + b1 * y4 + c1;
   258     /* Check signs of r3 and r4.  If both point 3 and point 4 lie on
   259      * same side of line 1, the line segments do not intersect.
   260      */
   262     if( r3 == 0 && r4 == 0 ) {
   263 	return LINE_COLLINEAR;
   264     } else if( r3 <= 0 && r4 <= 0 ) {
   265 	return LINE_SIDE_LEFT;
   266     } else if( r3 >= 0 && r4 >= 0 ) {
   267 	return LINE_SIDE_RIGHT;
   268     }
   270     /* Compute a2, b2, c2 */
   272     a2 = y4 - y3;
   273     b2 = x3 - x4;
   274     c2 = x4 * y3 - x3 * y4;
   276     /* Compute r1 and r2 */
   278     r1 = a2 * x1 + b2 * y1 + c2;
   279     r2 = a2 * x2 + b2 * y2 + c2;
   281     /* Check signs of r1 and r2.  If both point 1 and point 2 lie
   282      * on same side of second line segment, the line segments do
   283      * not intersect.
   284      */
   286     if ( r1 != 0 && r2 != 0 &&
   287          signbit(r1) == signbit(r2) ) {
   288         return LINE_SKEW; /* Should never happen */
   289     }
   291     /* Cmpute intersection point. 
   292      */
   293     denom = a1 * b2 - a2 * b1;
   294     if ( denom == 0 )
   295         return LINE_COLLINEAR; /* Should never get to this point either */
   297     *x = (b1 * c2 - b2 * c1) / denom;
   298     *y = (a2 * c1 - a1 * c2) / denom;
   300     if( r3 <= 0 && r4 >= 0 ) {
   301 	return LINE_INTERSECT_FROM_LEFT;
   302     } else {
   303 	return LINE_INTERSECT_FROM_RIGHT;
   304     }
   305 }
   307 /**
   308  * Given a set of vertexes and a line segment to use to split them, generates
   309  * two sets of vertexes representing the polygon on either side of the line
   310  * segment. This method preserves the winding direction of the input vertexes.
   311  */
   312 static void compute_subregions( struct bkg_scene *scene,
   313 				int splitv1, int splitv2,
   314 				int *vertex_in, int num_vertex_in,
   315 				int *left_vertex_out, int *num_left_vertex_out,
   316 				int *right_vertex_out, int *num_right_vertex_out )
   317 {
   318     float x1 = scene->vertexes[splitv1].x;
   319     float y1 = scene->vertexes[splitv1].y;
   320     float x2 = scene->vertexes[splitv2].x;
   321     float y2 = scene->vertexes[splitv2].y;
   323     float a1 = y2 - y1;
   324     float b1 = x1 - x2;
   325     float c1 = x2 * y1 - x1 * y2;
   326     int i;
   328     *num_left_vertex_out = 0;
   329     *num_right_vertex_out = 0;
   330     int last = 0;
   331     for( i=0; i<num_vertex_in; i++ ) {
   332 	struct vertex_unpacked *vertex = &scene->vertexes[vertex_in[i]];
   333 	float r = a1 * vertex->x + b1 * vertex->y + c1;
   334 	if( r <= 0 ) {
   335 	    if( last == 1 ) {
   336 		/* cross-point. add the split vertexes */
   337 		int v1 = vertex_in[i-1];
   338 		int v2 = vertex_in[i];
   339 		/* Determine which point is closer to the line. Strictly speaking
   340 		 * one of them must be ON the line, but this way allows for floating
   341 		 * point inaccuracies.
   342 		 */
   343 		float a2 = scene->vertexes[v2].y - scene->vertexes[v1].y;
   344 		float b2 = scene->vertexes[v1].x - scene->vertexes[v2].x;
   345 		float c2 = scene->vertexes[v2].x * scene->vertexes[v1].y - 
   346 		    scene->vertexes[v1].x * scene->vertexes[v2].y;
   347 		float r1 = a2 * x1 + b2 * y1 + c2;
   348 		float r2 = a2 * x2 + b2 * y2 + c2;
   349 		if( fabsf(r1) > fabs(r2) ) {
   350 		    int tmp = splitv1;
   351 		    splitv1 = splitv2;
   352 		    splitv2 = tmp;
   353 		}
   354 		right_vertex_out[(*num_right_vertex_out)++] = splitv1;
   355 		right_vertex_out[(*num_right_vertex_out)++] = splitv2;
   356 		left_vertex_out[(*num_left_vertex_out)++] = splitv2;
   357 		left_vertex_out[(*num_left_vertex_out)++] = splitv1;
   358 		last = 2;
   359 	    } else if( last != 2 ) {
   360 		last = -1;
   361 	    }
   362 	    left_vertex_out[(*num_left_vertex_out)++] = vertex_in[i];
   363 	} else {
   364 	    if( last == -1 ) {
   365 		/* cross-point. add the split vertexes */
   366 		int v1 = vertex_in[i-1];
   367 		int v2 = vertex_in[i];
   368 		/* Determine which point is closer to the line. Strictly speaking
   369 		 * one of them must be ON the line, but this way allows for floating
   370 		 * point inaccuracies.
   371 		 */
   372 		float a2 = scene->vertexes[v2].y - scene->vertexes[v1].y;
   373 		float b2 = scene->vertexes[v1].x - scene->vertexes[v2].x;
   374 		float c2 = scene->vertexes[v2].x * scene->vertexes[v1].y - 
   375 		    scene->vertexes[v1].x * scene->vertexes[v2].y;
   376 		float r1 = a2 * x1 + b2 * y1 + c2;
   377 		float r2 = a2 * x2 + b2 * y2 + c2;
   378 		if( fabsf(r1) > fabs(r2) ) {
   379 		    int tmp = splitv1;
   380 		    splitv1 = splitv2;
   381 		    splitv2 = tmp;
   382 		}
   383 		left_vertex_out[(*num_left_vertex_out)++] = splitv1;
   384 		left_vertex_out[(*num_left_vertex_out)++] = splitv2;
   385 		right_vertex_out[(*num_right_vertex_out)++] = splitv2;
   386 		right_vertex_out[(*num_right_vertex_out)++] = splitv1;
   387 		last = 2;
   388 	    } else if( last != 2 ) {
   389 		last = 1;
   390 	    }
   391 	    right_vertex_out[(*num_right_vertex_out)++] = vertex_in[i];
   392 	}
   393     }
   394 }
   396 /**
   397  * Subdivide the region tree by splitting it along a given line.
   398  * 
   399  * @param scene  current bkg scene data
   400  * @param region current region under examination
   401  * @param vertex1 first vertex of the new line segment
   402  * @param vertex2 second vertex of the new line segment
   403  */
   404 static void bkg_region_subdivide( struct bkg_scene *scene, int region, int vertex1, int vertex2 ) {
   405     struct bkg_region *this_region = &scene->regions[region];
   407     if( scene->regions[region].region_left == -1 || scene->regions[region].region_right == -1 ) {
   408 	/* Reached the end of the tree. Setup new left+right regions */
   409 	int i = scene->num_regions;
   410 	scene->regions[i].region_left = scene->regions[i].region_right = -1;
   411 	scene->regions[i+1].region_left = scene->regions[i+1].region_right = -1;
   412 	this_region->region_left = i;
   413 	this_region->region_right = i+1;
   414 	this_region->vertex1 = vertex1;
   415 	this_region->vertex2 = vertex2;
   416 	scene->num_regions += 2;
   417     } else {
   418 	float x,y;
   419 	int thisv1 = this_region->vertex1;
   420 	int thisv2 = this_region->vertex2;
   421 	int vertex3;
   422 	int status = 
   423 	    compute_line_intersection( scene->vertexes[thisv1].x, scene->vertexes[thisv1].y,
   424 				       scene->vertexes[thisv2].x, scene->vertexes[thisv2].y,
   425 				       scene->vertexes[vertex1].x, scene->vertexes[vertex1].y,
   426 				       scene->vertexes[vertex2].x, scene->vertexes[vertex2].y,
   427 				       &x, &y );
   428 	switch( status ) {
   429 	case LINE_INTERSECT_FROM_LEFT:
   430 	    /* if new line segment intersects our current line segment,
   431 	     * subdivide the segment (add a new vertex) and recurse on both
   432 	     * sub trees 
   433 	     */
   434 	    /* Compute split-point vertex */
   435 	    vertex3 = scene->num_vertexes++;
   436 	    scene->vertexes[vertex3].x = x;
   437 	    scene->vertexes[vertex3].y = y;
   438 	    /* Recurse */
   439 	    bkg_region_subdivide( scene, scene->regions[region].region_left, vertex1,vertex3 );
   440 	    bkg_region_subdivide( scene, scene->regions[region].region_right, vertex3, vertex2 );
   441 	    break;
   442 	case LINE_INTERSECT_FROM_RIGHT:
   443 	    /* Same except line runs in the opposite direction */
   444 	    vertex3 = scene->num_vertexes++;
   445 	    scene->vertexes[vertex3].x = x;
   446 	    scene->vertexes[vertex3].y = y;
   447 	    /* Recurse */
   448 	    bkg_region_subdivide( scene, scene->regions[region].region_left, vertex2,vertex3 );
   449 	    bkg_region_subdivide( scene, scene->regions[region].region_right, vertex3, vertex1 );
   450 	    break;
   451 	case LINE_COLLINEAR:
   452 	case LINE_SKEW:
   453 	    /* Collinear - ignore */
   454 	    break;
   455 	case LINE_SIDE_LEFT:
   456 	    /* else if line segment passes through the left sub-region alone,
   457 	     * left-recurse only.
   458 	     */
   459 	    bkg_region_subdivide( scene, scene->regions[region].region_left, vertex1, vertex2 );
   460 	    break;
   461 	case LINE_SIDE_RIGHT:
   462 	    /* Otherwise line segment passes through the right sub-region alone,
   463 	     * so right-recurse.
   464 	     */
   465 	    bkg_region_subdivide( scene, scene->regions[region].region_right, vertex1, vertex2 );
   466 	    break;
   467 	}
   468     }
   469 }
   473 /**
   474  * Compute the values for an array of vertexes, given x,y for each
   475  * vertex and the base 3-vertex triple used to define the background
   476  * plane. Essentially the base vertexes are used to find the
   477  * plane equation for each of z,a,r,g,b,etc, which is then solved for
   478  * each of the required compute vertexes (normally the corner points).
   479  *
   480  * @param base The 3 vertexes supplied as the background definition
   481  * @param compute An array of vertexes to compute. x and y must be
   482  *   preset, other values are computed.
   483  */
   484 static void bkg_compute_scene( struct vertex_unpacked *base, int width, int height,
   485 				struct bkg_scene *scene )
   486 {
   487     struct vertex_unpacked center;
   488     struct vertex_unpacked diff0, diff1;
   489     int i,k;
   491     center.x = base[1].x;
   492     center.y = base[1].y;
   493     center.z = base[1].z;
   494     center.u = base[1].u;
   495     center.v = base[1].v;
   496     diff0.x = base[0].x - center.x;
   497     diff0.y = base[0].y - center.y;
   498     diff0.z = base[0].z - center.z;
   499     diff1.x = base[2].x - center.x;
   500     diff1.y = base[2].y - center.y;
   501     diff1.z = base[2].z - center.z;
   503     float detxy = ((diff1.y) * (diff0.x)) - ((diff0.y) * (diff1.x));
   505     /* Corner points first */
   506     scene->vertexes[0].x = 0.0;
   507     scene->vertexes[0].y = 0.0;
   508     scene->vertexes[1].x = width;
   509     scene->vertexes[1].y = 0.0;
   510     scene->vertexes[2].x = width;
   511     scene->vertexes[2].y = height;
   512     scene->vertexes[3].x = 0.0;
   513     scene->vertexes[3].y = height;
   514     scene->regions[0].region_left = -1;
   515     scene->regions[0].region_right = -1;
   516     scene->num_vertexes = 4;
   517     scene->num_regions = 1;
   519     if( detxy == 0 ) {
   520 	/* The points lie on a single line - no plane for you. Use the values
   521 	 * from the 3rd point for the whole screen.
   522 	 */
   523 	for( i=0; i<4; i++ ) {
   524 	    scene->vertexes[i].rgba[0] = base[2].rgba[0];
   525 	    scene->vertexes[i].rgba[1] = base[2].rgba[1];
   526 	    scene->vertexes[i].rgba[2] = base[2].rgba[2];
   527 	    scene->vertexes[i].rgba[3] = base[2].rgba[3];
   528 	    scene->vertexes[i].z = base[2].z;
   529 	    scene->vertexes[i].u = base[2].u;
   530 	    scene->vertexes[i].v = base[2].v;
   531 	}
   532     } else {
   533 	/* Compute the colour values at each corner */
   534 	center.rgba[0] = base[1].rgba[0];
   535 	center.rgba[1] = base[1].rgba[1];
   536 	center.rgba[2] = base[1].rgba[2];
   537 	center.rgba[3] = base[1].rgba[3];
   538 	diff0.rgba[0] = base[0].rgba[0] - center.rgba[0];
   539 	diff0.rgba[1] = base[0].rgba[1] - center.rgba[1];
   540 	diff0.rgba[2] = base[0].rgba[2] - center.rgba[2];
   541 	diff0.rgba[3] = base[0].rgba[3] - center.rgba[3];
   542 	diff0.u = base[0].u - center.u;
   543 	diff0.v = base[0].v - center.v;
   544 	diff1.rgba[0] = base[2].rgba[0] - center.rgba[0];
   545 	diff1.rgba[1] = base[2].rgba[1] - center.rgba[1];
   546 	diff1.rgba[2] = base[2].rgba[2] - center.rgba[2];
   547 	diff1.rgba[3] = base[2].rgba[3] - center.rgba[3];
   548 	diff1.u = base[2].u - center.u;
   549 	diff1.v = base[2].v - center.v;
   550 	for( i=0; i<4; i++ ) {
   551 	    float t = ((scene->vertexes[i].x - center.x) * diff1.y -
   552 		       (scene->vertexes[i].y - center.y) * diff1.x) / detxy;
   553 	    float s = ((scene->vertexes[i].y - center.y) * diff0.x -
   554 		       (scene->vertexes[i].x - center.x) * diff0.y) / detxy;
   555 	    scene->vertexes[i].z = center.z + (t*diff0.z) + (s*diff1.z);
   556 	    scene->vertexes[i].rgba[0] = center.rgba[0] + (t*diff0.rgba[0]) + (s*diff1.rgba[0]);
   557 	    scene->vertexes[i].rgba[1] = center.rgba[1] + (t*diff0.rgba[1]) + (s*diff1.rgba[1]);
   558 	    scene->vertexes[i].rgba[2] = center.rgba[2] + (t*diff0.rgba[2]) + (s*diff1.rgba[2]);
   559 	    scene->vertexes[i].rgba[3] = center.rgba[3] + (t*diff0.rgba[3]) + (s*diff1.rgba[3]);
   560 	    scene->vertexes[i].u = center.u + (t*diff0.u) + (s*diff1.u);
   561 	    scene->vertexes[i].v = center.v + (t*diff0.v) + (s*diff1.v);
   562 	}
   564 	/* Check for values > 1.0 | < 0.0 */
   565 	for( k=0; k<4; k++ ) {
   566 	    float detyk = ((diff1.y) * (diff0.rgba[k])) - ((diff0.y)*(diff1.rgba[k]));
   567 	    float detxk = ((diff0.x) * (diff1.rgba[k])) - ((diff1.x)*(diff0.rgba[k]));
   568 	    if( scene->vertexes[0].rgba[k] > 1.0 || scene->vertexes[1].rgba[k] > 1.0 || 
   569 		scene->vertexes[2].rgba[k] > 1.0 || scene->vertexes[3].rgba[k] > 1.0 ) {
   570 		int v1 = scene->num_vertexes;
   571 		scene->num_vertexes += compute_colour_line(center.x, center.y, center.rgba[k],
   572 						    width, height, 1.0,
   573 						    detxy, detxk, detyk, 
   574 						    scene->vertexes+scene->num_vertexes );
   575 		if( scene->num_vertexes != v1 ) {
   576 		    bkg_region_subdivide( scene, 0, v1, v1+1 );
   577 		}
   578 	    }
   580 	    if( scene->vertexes[0].rgba[k] < 0.0 || scene->vertexes[1].rgba[k] < 0.0 || 
   581 		scene->vertexes[2].rgba[k] < 0.0 || scene->vertexes[3].rgba[k] < 0.0 ) {
   582 		int v1 = scene->num_vertexes;
   583 		scene->num_vertexes += compute_colour_line(center.x, center.y, center.rgba[k],
   584 						    width, height, 0.0,
   585 						    detxy, detxk, detyk, 
   586 						    scene->vertexes+scene->num_vertexes );
   587 		if( scene->num_vertexes != v1 ) {
   588 		    bkg_region_subdivide( scene, 0, v1, v1+1 );
   589 		}
   591 	    }
   592 	}
   594 	/* Finally compute the colour values for all vertexes 
   595 	 * (excluding the 4 we did upfront) */
   596 	for( i=4; i<scene->num_vertexes; i++ ) {
   597 	    float t = ((scene->vertexes[i].x - center.x) * diff1.y -
   598 		       (scene->vertexes[i].y - center.y) * diff1.x) / detxy;
   599 	    float s = ((scene->vertexes[i].y - center.y) * diff0.x -
   600 		       (scene->vertexes[i].x - center.x) * diff0.y) / detxy;
   601 	    scene->vertexes[i].z = center.z + (t*diff0.z) + (s*diff1.z);
   602 	    scene->vertexes[i].rgba[0] = center.rgba[0] + (t*diff0.rgba[0]) + (s*diff1.rgba[0]);
   603 	    scene->vertexes[i].rgba[1] = center.rgba[1] + (t*diff0.rgba[1]) + (s*diff1.rgba[1]);
   604 	    scene->vertexes[i].rgba[2] = center.rgba[2] + (t*diff0.rgba[2]) + (s*diff1.rgba[2]);
   605 	    scene->vertexes[i].rgba[3] = center.rgba[3] + (t*diff0.rgba[3]) + (s*diff1.rgba[3]);
   606 	    scene->vertexes[i].u = center.u + (t*diff0.u) + (s*diff1.u);
   607 	    scene->vertexes[i].v = center.v + (t*diff0.v) + (s*diff1.v);
   608 	}
   609     }
   610 }
   612 /**
   613  * Render a bkg_region.
   614  * @param scene the background scene data
   615  * @param region the region to render
   616  * @param vertexes the vertexes surrounding the region
   617  * @param num_vertexes the number of vertexes in the vertex array
   618  */
   619 void bkg_render_region( struct bkg_scene *scene, int region, int *vertexes, int num_vertexes,
   620 			uint32_t poly1 )
   621 {
   622     if( scene->regions[region].region_left == -1 && scene->regions[region].region_right == -1 ) {
   623 	/* Leaf node - render the points as given */
   624 	int i,k;
   625 	glBegin(GL_POLYGON);
   626 	for( i=0; i<num_vertexes; i++ ) {
   627 	    k = vertexes[i];
   628 	    glColor4fv(scene->vertexes[k].rgba);
   629 	    if( POLY1_TEXTURED(poly1) ) {
   630 		glTexCoord2f(scene->vertexes[k].u, scene->vertexes[k].v);
   631 	    }
   632 	    glVertex3f(scene->vertexes[k].x, scene->vertexes[k].y, scene->vertexes[k].z);
   633 	}
   634 	glEnd();
   635     } else {
   636 	/* split the region into left and right regions */
   637 	int left_vertexes[num_vertexes+1];
   638 	int right_vertexes[num_vertexes+1];
   639 	int num_left = 0;
   640 	int num_right = 0;
   641 	struct bkg_region *reg = &scene->regions[region];
   642 	compute_subregions( scene, reg->vertex1, reg->vertex2, vertexes, num_vertexes,
   643 			    left_vertexes, &num_left, right_vertexes, &num_right );
   644 	bkg_render_region( scene, reg->region_left, left_vertexes, num_left, poly1 );
   645 	bkg_render_region( scene, reg->region_right, right_vertexes, num_right, poly1 );
   646     }
   648 }
   651 void render_backplane( uint32_t *polygon, uint32_t width, uint32_t height, uint32_t mode ) {
   652     struct vertex_unpacked vertex[3];
   653     int screen_vertexes[4] = {0,1,2,3};
   654     struct bkg_scene scene;
   655     int vertex_length = (mode >> 24) & 0x07;
   656     int cheap_shadow = MMIO_READ( PVR2, RENDER_SHADOW ) & 0x100;
   657     int is_modified = mode & 0x08000000;
   658     int context_length = 3;
   659     if( is_modified && !cheap_shadow ) {
   660 	context_length = 5;
   661 	vertex_length *= 2;
   662     }
   663     vertex_length += 3;
   664     context_length += (mode & 0x07) * vertex_length;
   667     render_unpack_vertexes( vertex, *polygon, polygon+context_length, 3, vertex_length,
   668 			    RENDER_NORMAL );
   669     bkg_compute_scene(vertex, width, height, &scene);
   670     render_set_context(polygon, RENDER_NORMAL);
   671     glDisable(GL_CULL_FACE);
   672     glDisable(GL_DEPTH_TEST);
   673     glBlendFunc(GL_ONE, GL_ZERO); /* For now, just disable alpha blending on the bkg */
   674     bkg_render_region(&scene, 0, screen_vertexes, 4, *polygon);
   675     glEnable(GL_CULL_FACE);
   676     glEnable(GL_DEPTH_TEST);
   677 }
.