Search
lxdream.org :: lxdream/src/pvr2/rendbkg.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/rendbkg.c
changeset 677:3ee62740ff8f
prev653:3202ff01d48e
author nkeynes
date Thu May 29 10:50:25 2008 +0000 (13 years ago)
permissions -rw-r--r--
last change Remove pvr2mmio.h include from pvr2.h (it's supposed to be moore or less private)
Move redraw function from driver into pvr2_redraw_display()
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 "pvr2/pvr2mmio.h"
    41 #include <math.h>
    43 #define MAX_CLAMP_LINES 8
    44 #define MAX_VERTEXES 256
    45 #define MAX_REGIONS  256
    47 #define FARGB_A(x) (((float)(((x)>>24)+1))/256.0)
    48 #define FARGB_R(x) (((float)((((x)>>16)&0xFF)+1))/256.0)
    49 #define FARGB_G(x) (((float)((((x)>>8)&0xFF)+1))/256.0)
    50 #define FARGB_B(x) (((float)(((x)&0xFF)+1))/256.0)
    52 /**
    53  * Convert a half-float (16-bit) FP number to a regular 32-bit float.
    54  * Source is 1-bit sign, 5-bit exponent, 10-bit mantissa.
    55  * TODO: Check the correctness of this.
    56  */
    57 static float halftofloat( uint16_t half )
    58 {
    59     union {
    60         float f;
    61         uint32_t i;
    62     } temp;
    63     /* int e = ((half & 0x7C00) >> 10) - 15 + 127;
    65     temp.i = ((half & 0x8000) << 16) | (e << 23) |
    66     ((half & 0x03FF) << 13); */
    67     temp.i = ((uint32_t)half)<<16;
    68     return temp.f;
    69 }
    71 void render_unpack_vertexes( struct vertex_unpacked *out, uint32_t poly1, 
    72 			     uint32_t *vertexes, int num_vertexes,
    73 			     int vertex_size, int render_mode )
    74 {
    75     int m = 0, i;
    76     if( render_mode == RENDER_FULLMOD ) {
    77 	m = (vertex_size - 3)/2;
    78     }
    80     for( i=0; i<num_vertexes; i++ ) {
    81 	float *vertexf = (float *)vertexes;
    82 	int k = m + 3;
    83 	out[i].x = vertexf[0];
    84 	out[i].y = vertexf[1];
    85 	out[i].z = vertexf[2];
    86     	if( POLY1_TEXTURED(poly1) ) {
    87 	    if( POLY1_UV16(poly1) ) {
    88 		out[i].u = halftofloat(vertexes[k]>>16);
    89 		out[i].v = halftofloat(vertexes[k]);
    90 		k++;
    91 	    } else {
    92 		out[i].u = vertexf[k];
    93 		out[i].v = vertexf[k+1];
    94 		k+=2;
    95 	    }
    96 	} else {
    97 	    out[i].u = 0;
    98 	    out[i].v = 0;
    99 	}
   100 	uint32_t argb = vertexes[k++];
   101 	out[i].rgba[0] = FARGB_R(argb);
   102 	out[i].rgba[1] = FARGB_G(argb);
   103         out[i].rgba[2] = FARGB_B(argb);
   104 	out[i].rgba[3] = FARGB_A(argb);
   105 	if( POLY1_SPECULAR(poly1) ) {
   106 	    uint32_t offset = vertexes[k++];
   107 	    out[i].offset_rgba[0] = FARGB_R(offset);
   108 	    out[i].offset_rgba[1] = FARGB_G(offset);
   109 	    out[i].offset_rgba[2] = FARGB_B(offset);
   110 	    out[i].offset_rgba[3] = FARGB_A(offset);
   111 	}
   112 	vertexes += vertex_size;
   113     }
   114 }
   116 /**
   117  * Compute the line where k = target_k, (where k is normally one of
   118  * r,g,b,a, or z) and determines the points at which the line intersects
   119  * the viewport (0,0,width,height).
   120  *
   121  * @param center_x the x value for the center position
   122  * @param center_y the y value for the center position
   123  * @param center_k the k value for the center position
   124  * @param width Width of the viewport (ie 640)
   125  * @param height Height of the viewport (ie 480)
   126  * @param target_k determine the line where k = this value, ie 1.0
   127  * @param detxy
   128  * @param target Array to write the resultant x,y pairs to (note this
   129  * function only sets x and y values).
   130  * @return number of vertexes written to the target.
   131  */
   132 static int compute_colour_line( float center_x, float center_y, float center_k, 
   133 		  int width, int height, float target_k,
   134 		  float detxy, float detxk, float detyk,
   135 		  struct vertex_unpacked *target ) {
   136     int num_points = 0;
   137     float tmpk = (target_k - center_k) * detxy;
   138     float x0 = -1;
   139     float x1 = -1;
   141     if( detyk != 0 ) {
   142 	x0 = (tmpk - ((0-center_y)*detxk))/detyk + center_x; /* x where y=0 */
   143 	if( x0 >= 0.0 && x0 <= width ) {
   144 	    target[num_points].x = x0;
   145 	    target[num_points].y = 0.0;
   146 	    num_points++;
   147 	}
   149 	x1 = (tmpk - ((height-center_y)*detxk))/detyk + center_x; /* x where y=height */
   150 	if( x1 >= 0.0 && x1 <= width ) {
   151 	    target[num_points].x = x1;
   152 	    target[num_points].y = height;
   153 	    num_points++;
   154 	}
   155     }
   157     if( detxk != 0 ) {
   158 	if( x0 != 0.0 && x1 != 0.0 ) { /* If x0 == 0 or x1 == 0, then we already have this one */
   159 	    float y0 = (tmpk - ((0-center_x)*detyk))/detxk + center_y; /* y where x=0 */
   160 	    if( y0 >= 0.0 && y0 <= height ) {
   161 		target[num_points].x = 0.0;
   162 		target[num_points].y = y0;
   163 		num_points++;
   164 	    }
   165 	}
   167 	if( x0 != width && x1 != width ) {
   168 	    float y1 = (tmpk - ((width-center_x)*detyk))/detxk + center_y; /* y where x=width */
   169 	    if( y1 >= 0.0 && y1 <= height ) {
   170 		target[num_points].x = width;
   171 		target[num_points].y = y1;
   172 		num_points++;
   173 	    }
   174 	}
   175     }
   177     if( num_points == 0 || num_points == 2 ) {
   178 	/* 0 = no points - line doesn't pass through the viewport */
   179 	/* 2 = normal case - got 2 endpoints */
   180 	return num_points;
   181     } else {
   182 	ERROR( "compute_colour_line got bad number of points: %d", num_points );
   183 	return 0;
   184     }
   185 }
   187 /**
   188  * A region describes a portion of the screen, possibly subdivided by a line.
   189  * if region_left and region_right are -1, this is a terminal region that can
   190  * be rendered directly. Otherwise region_left and region_right refer two 
   191  * sub-regions that are separated by the line segment vertex1-vertex2.
   192  */
   193 struct bkg_region {
   194     /* Vertexes marking the line segment that splits this region */
   195     int vertex1;
   196     int vertex2;
   197     /* Index of the left sub-region */
   198     int region_left;
   199     /* Index of the right sub-region */
   200     int region_right;
   201 };
   203 /**
   204  * Convenience structure to bundle together the vertex and region data.
   205  */
   206 struct bkg_scene {
   207     int num_vertexes;
   208     int num_regions;
   209     struct vertex_unpacked vertexes[MAX_VERTEXES];
   210     struct bkg_region regions[MAX_REGIONS];
   211 };
   213 /**
   214  * Constants returned by compute_line_intersection. Note that for these purposes,
   215  * "Left" means the point(s) result in a negative value in the line equation, while
   216  * "Right" means the points(s) result in a positive value in the line equation. The
   217  * exact meaning isn't particularly important though, as long as we're consistent
   218  * throughout this process
   219  */
   220 #define LINE_COLLINEAR 0   /* The line segments are part of the same line */
   221 #define LINE_SIDE_LEFT 1   /* The second line is entirely to the "left" of the first line */
   222 #define LINE_SIDE_RIGHT 2  /* The second line is entirely to the "right" of the first line */
   223 #define LINE_INTERSECT_FROM_LEFT 3 /* The lines intersect, and (x3,y3) is to the "left" of the first line */
   224 #define LINE_INTERSECT_FROM_RIGHT 4 /* The lines intersect, and (x3,y3) is to the "right" of the first line */
   225 #define LINE_SKEW 5        /* The line segments neither intersect nor do any of the above apply (should never happen here) */
   227 /**
   228  * Compute the intersection of two line segments, where 
   229  * (x1,y1)-(x2,y2) defines the target segment, and
   230  * (x3,y3)-(x4,y4) defines the line intersecting it.
   231  *
   232  * Based off work by Mukesh Prasad (http://www.acm.org/pubs/tog/GraphicsGems/index.html)
   233  *
   234  * @return one of the above LINE_* constants
   235  */
   236 static int compute_line_intersection( float x1, float y1,   /* First line segment */
   237 				      float x2, float y2,
   238 				      float x3, float y3,   /* Second line segment */
   239 				      float x4, float y4,
   240 				      float *x, float *y  )  /* Output value: */
   241 {
   242     float a1, a2, b1, b2, c1, c2; /* Coefficients of line eqns. */
   243     float r1, r2, r3, r4;         /* test values */
   244     float denom;     /* Intermediate values */
   246     /* Compute a1, b1, c1, where line joining points 1 and 2
   247      * is "a1 x  +  b1 y  +  c1  =  0".
   248      */
   250     a1 = y2 - y1;
   251     b1 = x1 - x2;
   252     c1 = x2 * y1 - x1 * y2;
   254     /* Compute r3 and r4. */
   256     r3 = a1 * x3 + b1 * y3 + c1;
   257     r4 = a1 * x4 + b1 * y4 + c1;
   259     /* Check signs of r3 and r4.  If both point 3 and point 4 lie on
   260      * same side of line 1, the line segments do not intersect.
   261      */
   263     if( r3 == 0 && r4 == 0 ) {
   264 	return LINE_COLLINEAR;
   265     } else if( r3 <= 0 && r4 <= 0 ) {
   266 	return LINE_SIDE_LEFT;
   267     } else if( r3 >= 0 && r4 >= 0 ) {
   268 	return LINE_SIDE_RIGHT;
   269     }
   271     /* Compute a2, b2, c2 */
   273     a2 = y4 - y3;
   274     b2 = x3 - x4;
   275     c2 = x4 * y3 - x3 * y4;
   277     /* Compute r1 and r2 */
   279     r1 = a2 * x1 + b2 * y1 + c2;
   280     r2 = a2 * x2 + b2 * y2 + c2;
   282     /* Check signs of r1 and r2.  If both point 1 and point 2 lie
   283      * on same side of second line segment, the line segments do
   284      * not intersect.
   285      */
   287     if ( r1 != 0 && r2 != 0 &&
   288          signbit(r1) == signbit(r2) ) {
   289         return LINE_SKEW; /* Should never happen */
   290     }
   292     /* Cmpute intersection point. 
   293      */
   294     denom = a1 * b2 - a2 * b1;
   295     if ( denom == 0 )
   296         return LINE_COLLINEAR; /* Should never get to this point either */
   298     *x = (b1 * c2 - b2 * c1) / denom;
   299     *y = (a2 * c1 - a1 * c2) / denom;
   301     if( r3 <= 0 && r4 >= 0 ) {
   302 	return LINE_INTERSECT_FROM_LEFT;
   303     } else {
   304 	return LINE_INTERSECT_FROM_RIGHT;
   305     }
   306 }
   308 /**
   309  * Given a set of vertexes and a line segment to use to split them, generates
   310  * two sets of vertexes representing the polygon on either side of the line
   311  * segment. This method preserves the winding direction of the input vertexes.
   312  */
   313 static void compute_subregions( struct bkg_scene *scene,
   314 				int splitv1, int splitv2,
   315 				int *vertex_in, int num_vertex_in,
   316 				int *left_vertex_out, int *num_left_vertex_out,
   317 				int *right_vertex_out, int *num_right_vertex_out )
   318 {
   319     float x1 = scene->vertexes[splitv1].x;
   320     float y1 = scene->vertexes[splitv1].y;
   321     float x2 = scene->vertexes[splitv2].x;
   322     float y2 = scene->vertexes[splitv2].y;
   324     float a1 = y2 - y1;
   325     float b1 = x1 - x2;
   326     float c1 = x2 * y1 - x1 * y2;
   327     int i;
   329     *num_left_vertex_out = 0;
   330     *num_right_vertex_out = 0;
   331     int last = 0;
   332     for( i=0; i<num_vertex_in; i++ ) {
   333 	struct vertex_unpacked *vertex = &scene->vertexes[vertex_in[i]];
   334 	float r = a1 * vertex->x + b1 * vertex->y + c1;
   335 	if( r <= 0 ) {
   336 	    if( last == 1 ) {
   337 		/* cross-point. add the split vertexes */
   338 		int v1 = vertex_in[i-1];
   339 		int v2 = vertex_in[i];
   340 		/* Determine which point is closer to the line. Strictly speaking
   341 		 * one of them must be ON the line, but this way allows for floating
   342 		 * point inaccuracies.
   343 		 */
   344 		float a2 = scene->vertexes[v2].y - scene->vertexes[v1].y;
   345 		float b2 = scene->vertexes[v1].x - scene->vertexes[v2].x;
   346 		float c2 = scene->vertexes[v2].x * scene->vertexes[v1].y - 
   347 		    scene->vertexes[v1].x * scene->vertexes[v2].y;
   348 		float r1 = a2 * x1 + b2 * y1 + c2;
   349 		float r2 = a2 * x2 + b2 * y2 + c2;
   350 		if( fabsf(r1) > fabs(r2) ) {
   351 		    int tmp = splitv1;
   352 		    splitv1 = splitv2;
   353 		    splitv2 = tmp;
   354 		}
   355 		right_vertex_out[(*num_right_vertex_out)++] = splitv1;
   356 		right_vertex_out[(*num_right_vertex_out)++] = splitv2;
   357 		left_vertex_out[(*num_left_vertex_out)++] = splitv2;
   358 		left_vertex_out[(*num_left_vertex_out)++] = splitv1;
   359 		last = 2;
   360 	    } else if( last != 2 ) {
   361 		last = -1;
   362 	    }
   363 	    left_vertex_out[(*num_left_vertex_out)++] = vertex_in[i];
   364 	} else {
   365 	    if( last == -1 ) {
   366 		/* cross-point. add the split vertexes */
   367 		int v1 = vertex_in[i-1];
   368 		int v2 = vertex_in[i];
   369 		/* Determine which point is closer to the line. Strictly speaking
   370 		 * one of them must be ON the line, but this way allows for floating
   371 		 * point inaccuracies.
   372 		 */
   373 		float a2 = scene->vertexes[v2].y - scene->vertexes[v1].y;
   374 		float b2 = scene->vertexes[v1].x - scene->vertexes[v2].x;
   375 		float c2 = scene->vertexes[v2].x * scene->vertexes[v1].y - 
   376 		    scene->vertexes[v1].x * scene->vertexes[v2].y;
   377 		float r1 = a2 * x1 + b2 * y1 + c2;
   378 		float r2 = a2 * x2 + b2 * y2 + c2;
   379 		if( fabsf(r1) > fabs(r2) ) {
   380 		    int tmp = splitv1;
   381 		    splitv1 = splitv2;
   382 		    splitv2 = tmp;
   383 		}
   384 		left_vertex_out[(*num_left_vertex_out)++] = splitv1;
   385 		left_vertex_out[(*num_left_vertex_out)++] = splitv2;
   386 		right_vertex_out[(*num_right_vertex_out)++] = splitv2;
   387 		right_vertex_out[(*num_right_vertex_out)++] = splitv1;
   388 		last = 2;
   389 	    } else if( last != 2 ) {
   390 		last = 1;
   391 	    }
   392 	    right_vertex_out[(*num_right_vertex_out)++] = vertex_in[i];
   393 	}
   394     }
   395 }
   397 /**
   398  * Subdivide the region tree by splitting it along a given line.
   399  * 
   400  * @param scene  current bkg scene data
   401  * @param region current region under examination
   402  * @param vertex1 first vertex of the new line segment
   403  * @param vertex2 second vertex of the new line segment
   404  */
   405 static void bkg_region_subdivide( struct bkg_scene *scene, int region, int vertex1, int vertex2 ) {
   406     struct bkg_region *this_region = &scene->regions[region];
   408     if( scene->regions[region].region_left == -1 || scene->regions[region].region_right == -1 ) {
   409 	/* Reached the end of the tree. Setup new left+right regions */
   410 	int i = scene->num_regions;
   411 	scene->regions[i].region_left = scene->regions[i].region_right = -1;
   412 	scene->regions[i+1].region_left = scene->regions[i+1].region_right = -1;
   413 	this_region->region_left = i;
   414 	this_region->region_right = i+1;
   415 	this_region->vertex1 = vertex1;
   416 	this_region->vertex2 = vertex2;
   417 	scene->num_regions += 2;
   418     } else {
   419 	float x,y;
   420 	int thisv1 = this_region->vertex1;
   421 	int thisv2 = this_region->vertex2;
   422 	int vertex3;
   423 	int status = 
   424 	    compute_line_intersection( scene->vertexes[thisv1].x, scene->vertexes[thisv1].y,
   425 				       scene->vertexes[thisv2].x, scene->vertexes[thisv2].y,
   426 				       scene->vertexes[vertex1].x, scene->vertexes[vertex1].y,
   427 				       scene->vertexes[vertex2].x, scene->vertexes[vertex2].y,
   428 				       &x, &y );
   429 	switch( status ) {
   430 	case LINE_INTERSECT_FROM_LEFT:
   431 	    /* if new line segment intersects our current line segment,
   432 	     * subdivide the segment (add a new vertex) and recurse on both
   433 	     * sub trees 
   434 	     */
   435 	    /* Compute split-point vertex */
   436 	    vertex3 = scene->num_vertexes++;
   437 	    scene->vertexes[vertex3].x = x;
   438 	    scene->vertexes[vertex3].y = y;
   439 	    /* Recurse */
   440 	    bkg_region_subdivide( scene, scene->regions[region].region_left, vertex1,vertex3 );
   441 	    bkg_region_subdivide( scene, scene->regions[region].region_right, vertex3, vertex2 );
   442 	    break;
   443 	case LINE_INTERSECT_FROM_RIGHT:
   444 	    /* Same except line runs in the opposite direction */
   445 	    vertex3 = scene->num_vertexes++;
   446 	    scene->vertexes[vertex3].x = x;
   447 	    scene->vertexes[vertex3].y = y;
   448 	    /* Recurse */
   449 	    bkg_region_subdivide( scene, scene->regions[region].region_left, vertex2,vertex3 );
   450 	    bkg_region_subdivide( scene, scene->regions[region].region_right, vertex3, vertex1 );
   451 	    break;
   452 	case LINE_COLLINEAR:
   453 	case LINE_SKEW:
   454 	    /* Collinear - ignore */
   455 	    break;
   456 	case LINE_SIDE_LEFT:
   457 	    /* else if line segment passes through the left sub-region alone,
   458 	     * left-recurse only.
   459 	     */
   460 	    bkg_region_subdivide( scene, scene->regions[region].region_left, vertex1, vertex2 );
   461 	    break;
   462 	case LINE_SIDE_RIGHT:
   463 	    /* Otherwise line segment passes through the right sub-region alone,
   464 	     * so right-recurse.
   465 	     */
   466 	    bkg_region_subdivide( scene, scene->regions[region].region_right, vertex1, vertex2 );
   467 	    break;
   468 	}
   469     }
   470 }
   474 /**
   475  * Compute the values for an array of vertexes, given x,y for each
   476  * vertex and the base 3-vertex triple used to define the background
   477  * plane. Essentially the base vertexes are used to find the
   478  * plane equation for each of z,a,r,g,b,etc, which is then solved for
   479  * each of the required compute vertexes (normally the corner points).
   480  *
   481  * @param base The 3 vertexes supplied as the background definition
   482  * @param compute An array of vertexes to compute. x and y must be
   483  *   preset, other values are computed.
   484  */
   485 static void bkg_compute_scene( struct vertex_unpacked *base, int width, int height,
   486 				struct bkg_scene *scene )
   487 {
   488     struct vertex_unpacked center;
   489     struct vertex_unpacked diff0, diff1;
   490     int i,k;
   492     center.x = base[1].x;
   493     center.y = base[1].y;
   494     center.z = base[1].z;
   495     center.u = base[1].u;
   496     center.v = base[1].v;
   497     diff0.x = base[0].x - center.x;
   498     diff0.y = base[0].y - center.y;
   499     diff0.z = base[0].z - center.z;
   500     diff1.x = base[2].x - center.x;
   501     diff1.y = base[2].y - center.y;
   502     diff1.z = base[2].z - center.z;
   504     float detxy = ((diff1.y) * (diff0.x)) - ((diff0.y) * (diff1.x));
   506     /* Corner points first */
   507     scene->vertexes[0].x = 0.0;
   508     scene->vertexes[0].y = 0.0;
   509     scene->vertexes[1].x = width;
   510     scene->vertexes[1].y = 0.0;
   511     scene->vertexes[2].x = width;
   512     scene->vertexes[2].y = height;
   513     scene->vertexes[3].x = 0.0;
   514     scene->vertexes[3].y = height;
   515     scene->regions[0].region_left = -1;
   516     scene->regions[0].region_right = -1;
   517     scene->num_vertexes = 4;
   518     scene->num_regions = 1;
   520     if( detxy == 0 ) {
   521 	/* The points lie on a single line - no plane for you. Use the values
   522 	 * from the 3rd point for the whole screen.
   523 	 */
   524 	for( i=0; i<4; i++ ) {
   525 	    scene->vertexes[i].rgba[0] = base[2].rgba[0];
   526 	    scene->vertexes[i].rgba[1] = base[2].rgba[1];
   527 	    scene->vertexes[i].rgba[2] = base[2].rgba[2];
   528 	    scene->vertexes[i].rgba[3] = base[2].rgba[3];
   529 	    scene->vertexes[i].z = base[2].z;
   530 	    scene->vertexes[i].u = base[2].u;
   531 	    scene->vertexes[i].v = base[2].v;
   532 	}
   533     } else {
   534 	/* Compute the colour values at each corner */
   535 	center.rgba[0] = base[1].rgba[0];
   536 	center.rgba[1] = base[1].rgba[1];
   537 	center.rgba[2] = base[1].rgba[2];
   538 	center.rgba[3] = base[1].rgba[3];
   539 	diff0.rgba[0] = base[0].rgba[0] - center.rgba[0];
   540 	diff0.rgba[1] = base[0].rgba[1] - center.rgba[1];
   541 	diff0.rgba[2] = base[0].rgba[2] - center.rgba[2];
   542 	diff0.rgba[3] = base[0].rgba[3] - center.rgba[3];
   543 	diff0.u = base[0].u - center.u;
   544 	diff0.v = base[0].v - center.v;
   545 	diff1.rgba[0] = base[2].rgba[0] - center.rgba[0];
   546 	diff1.rgba[1] = base[2].rgba[1] - center.rgba[1];
   547 	diff1.rgba[2] = base[2].rgba[2] - center.rgba[2];
   548 	diff1.rgba[3] = base[2].rgba[3] - center.rgba[3];
   549 	diff1.u = base[2].u - center.u;
   550 	diff1.v = base[2].v - center.v;
   551 	for( i=0; i<4; i++ ) {
   552 	    float t = ((scene->vertexes[i].x - center.x) * diff1.y -
   553 		       (scene->vertexes[i].y - center.y) * diff1.x) / detxy;
   554 	    float s = ((scene->vertexes[i].y - center.y) * diff0.x -
   555 		       (scene->vertexes[i].x - center.x) * diff0.y) / detxy;
   556 	    scene->vertexes[i].z = center.z + (t*diff0.z) + (s*diff1.z);
   557 	    scene->vertexes[i].rgba[0] = center.rgba[0] + (t*diff0.rgba[0]) + (s*diff1.rgba[0]);
   558 	    scene->vertexes[i].rgba[1] = center.rgba[1] + (t*diff0.rgba[1]) + (s*diff1.rgba[1]);
   559 	    scene->vertexes[i].rgba[2] = center.rgba[2] + (t*diff0.rgba[2]) + (s*diff1.rgba[2]);
   560 	    scene->vertexes[i].rgba[3] = center.rgba[3] + (t*diff0.rgba[3]) + (s*diff1.rgba[3]);
   561 	    scene->vertexes[i].u = center.u + (t*diff0.u) + (s*diff1.u);
   562 	    scene->vertexes[i].v = center.v + (t*diff0.v) + (s*diff1.v);
   563 	}
   565 	/* Check for values > 1.0 | < 0.0 */
   566 	for( k=0; k<4; k++ ) {
   567 	    float detyk = ((diff1.y) * (diff0.rgba[k])) - ((diff0.y)*(diff1.rgba[k]));
   568 	    float detxk = ((diff0.x) * (diff1.rgba[k])) - ((diff1.x)*(diff0.rgba[k]));
   569 	    if( scene->vertexes[0].rgba[k] > 1.0 || scene->vertexes[1].rgba[k] > 1.0 || 
   570 		scene->vertexes[2].rgba[k] > 1.0 || scene->vertexes[3].rgba[k] > 1.0 ) {
   571 		int v1 = scene->num_vertexes;
   572 		scene->num_vertexes += compute_colour_line(center.x, center.y, center.rgba[k],
   573 						    width, height, 1.0,
   574 						    detxy, detxk, detyk, 
   575 						    scene->vertexes+scene->num_vertexes );
   576 		if( scene->num_vertexes != v1 ) {
   577 		    bkg_region_subdivide( scene, 0, v1, v1+1 );
   578 		}
   579 	    }
   581 	    if( scene->vertexes[0].rgba[k] < 0.0 || scene->vertexes[1].rgba[k] < 0.0 || 
   582 		scene->vertexes[2].rgba[k] < 0.0 || scene->vertexes[3].rgba[k] < 0.0 ) {
   583 		int v1 = scene->num_vertexes;
   584 		scene->num_vertexes += compute_colour_line(center.x, center.y, center.rgba[k],
   585 						    width, height, 0.0,
   586 						    detxy, detxk, detyk, 
   587 						    scene->vertexes+scene->num_vertexes );
   588 		if( scene->num_vertexes != v1 ) {
   589 		    bkg_region_subdivide( scene, 0, v1, v1+1 );
   590 		}
   592 	    }
   593 	}
   595 	/* Finally compute the colour values for all vertexes 
   596 	 * (excluding the 4 we did upfront) */
   597 	for( i=4; i<scene->num_vertexes; i++ ) {
   598 	    float t = ((scene->vertexes[i].x - center.x) * diff1.y -
   599 		       (scene->vertexes[i].y - center.y) * diff1.x) / detxy;
   600 	    float s = ((scene->vertexes[i].y - center.y) * diff0.x -
   601 		       (scene->vertexes[i].x - center.x) * diff0.y) / detxy;
   602 	    scene->vertexes[i].z = center.z + (t*diff0.z) + (s*diff1.z);
   603 	    scene->vertexes[i].rgba[0] = center.rgba[0] + (t*diff0.rgba[0]) + (s*diff1.rgba[0]);
   604 	    scene->vertexes[i].rgba[1] = center.rgba[1] + (t*diff0.rgba[1]) + (s*diff1.rgba[1]);
   605 	    scene->vertexes[i].rgba[2] = center.rgba[2] + (t*diff0.rgba[2]) + (s*diff1.rgba[2]);
   606 	    scene->vertexes[i].rgba[3] = center.rgba[3] + (t*diff0.rgba[3]) + (s*diff1.rgba[3]);
   607 	    scene->vertexes[i].u = center.u + (t*diff0.u) + (s*diff1.u);
   608 	    scene->vertexes[i].v = center.v + (t*diff0.v) + (s*diff1.v);
   609 	}
   610     }
   611 }
   613 /**
   614  * Render a bkg_region.
   615  * @param scene the background scene data
   616  * @param region the region to render
   617  * @param vertexes the vertexes surrounding the region
   618  * @param num_vertexes the number of vertexes in the vertex array
   619  */
   620 void bkg_render_region( struct bkg_scene *scene, int region, int *vertexes, int num_vertexes,
   621 			uint32_t poly1 )
   622 {
   623     if( scene->regions[region].region_left == -1 && scene->regions[region].region_right == -1 ) {
   624 	/* Leaf node - render the points as given */
   625 	int i,k;
   626 	glBegin(GL_POLYGON);
   627 	for( i=0; i<num_vertexes; i++ ) {
   628 	    k = vertexes[i];
   629 	    glColor4fv(scene->vertexes[k].rgba);
   630 	    if( POLY1_TEXTURED(poly1) ) {
   631 		glTexCoord2f(scene->vertexes[k].u, scene->vertexes[k].v);
   632 	    }
   633 	    glVertex3f(scene->vertexes[k].x, scene->vertexes[k].y, scene->vertexes[k].z);
   634 	}
   635 	glEnd();
   636     } else {
   637 	/* split the region into left and right regions */
   638 	int left_vertexes[num_vertexes+1];
   639 	int right_vertexes[num_vertexes+1];
   640 	int num_left = 0;
   641 	int num_right = 0;
   642 	struct bkg_region *reg = &scene->regions[region];
   643 	compute_subregions( scene, reg->vertex1, reg->vertex2, vertexes, num_vertexes,
   644 			    left_vertexes, &num_left, right_vertexes, &num_right );
   645 	bkg_render_region( scene, reg->region_left, left_vertexes, num_left, poly1 );
   646 	bkg_render_region( scene, reg->region_right, right_vertexes, num_right, poly1 );
   647     }
   649 }
   652 void render_backplane( uint32_t *polygon, uint32_t width, uint32_t height, uint32_t mode ) {
   653     struct vertex_unpacked vertex[3];
   654     int screen_vertexes[4] = {0,1,2,3};
   655     struct bkg_scene scene;
   656     int vertex_length = (mode >> 24) & 0x07;
   657     int cheap_shadow = MMIO_READ( PVR2, RENDER_SHADOW ) & 0x100;
   658     int is_modified = mode & 0x08000000;
   659     int context_length = 3;
   660     if( is_modified && !cheap_shadow ) {
   661 	context_length = 5;
   662 	vertex_length *= 2;
   663     }
   664     vertex_length += 3;
   665     context_length += (mode & 0x07) * vertex_length;
   668     render_unpack_vertexes( vertex, *polygon, polygon+context_length, 3, vertex_length,
   669 			    RENDER_NORMAL );
   670     bkg_compute_scene(vertex, width, height, &scene);
   671     render_set_context(polygon, RENDER_NORMAL);
   672     glDisable(GL_CULL_FACE);
   673     glDisable(GL_DEPTH_TEST);
   674     glBlendFunc(GL_ONE, GL_ZERO); /* For now, just disable alpha blending on the bkg */
   675     bkg_render_region(&scene, 0, screen_vertexes, 4, *polygon);
   676     glEnable(GL_CULL_FACE);
   677     glEnable(GL_DEPTH_TEST);
   678 }
.