nkeynes@219: /** nkeynes@561: * $Id$ nkeynes@219: * nkeynes@219: * PVR2 background renderer. nkeynes@219: * nkeynes@219: * Yes, it uses the same basic data structure. Yes, it needs to be handled nkeynes@219: * completely differently. nkeynes@219: * nkeynes@239: * PVR2 backgrounds are defined as a set of three fully specified vertexes, nkeynes@239: * stored in compiled-vertex format. The vertexes form a triangle which is nkeynes@239: * rendered in the normal fashion. Points outside the triangle are rendered nkeynes@239: * by extrapolating from the gradients established by the triangle, giving nkeynes@239: * an overall smooth gradient across the background. Points are colour-clamped nkeynes@239: * prior to output to the buffer. nkeynes@239: * nkeynes@239: * As a special case, if all three points lie on the same line (or are the same nkeynes@239: * point, the third point is used by itself to define the entire buffer (ie nkeynes@239: * effectively a solid colour). nkeynes@239: * nkeynes@221: * Note: this would be really simple if GL did unclamped colour interpolation nkeynes@221: * but it doesn't (portably), which makes this roughly 2 orders of magnitude nkeynes@221: * more complicated than it otherwise would be. nkeynes@221: * nkeynes@219: * Copyright (c) 2005 Nathan Keynes. nkeynes@219: * nkeynes@219: * This program is free software; you can redistribute it and/or modify nkeynes@219: * it under the terms of the GNU General Public License as published by nkeynes@219: * the Free Software Foundation; either version 2 of the License, or nkeynes@219: * (at your option) any later version. nkeynes@219: * nkeynes@219: * This program is distributed in the hope that it will be useful, nkeynes@219: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@219: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@219: * GNU General Public License for more details. nkeynes@219: */ nkeynes@219: nkeynes@219: #include nkeynes@540: #include "display.h" nkeynes@219: #include "pvr2/pvr2.h" nkeynes@221: #include nkeynes@219: nkeynes@221: #define MAX_CLAMP_LINES 8 nkeynes@221: #define MAX_VERTEXES 256 nkeynes@221: #define MAX_REGIONS 256 nkeynes@219: nkeynes@219: #define FARGB_A(x) (((float)(((x)>>24)+1))/256.0) nkeynes@219: #define FARGB_R(x) (((float)((((x)>>16)&0xFF)+1))/256.0) nkeynes@219: #define FARGB_G(x) (((float)((((x)>>8)&0xFF)+1))/256.0) nkeynes@219: #define FARGB_B(x) (((float)(((x)&0xFF)+1))/256.0) nkeynes@219: nkeynes@219: /** nkeynes@221: * Compute the line where k = target_k, (where k is normally one of nkeynes@221: * r,g,b,a, or z) and determines the points at which the line intersects nkeynes@221: * the viewport (0,0,width,height). nkeynes@221: * nkeynes@221: * @param center_x the x value for the center position nkeynes@221: * @param center_y the y value for the center position nkeynes@221: * @param center_k the k value for the center position nkeynes@221: * @param width Width of the viewport (ie 640) nkeynes@221: * @param height Height of the viewport (ie 480) nkeynes@221: * @param target_k determine the line where k = this value, ie 1.0 nkeynes@221: * @param detxy nkeynes@221: * @param target Array to write the resultant x,y pairs to (note this nkeynes@221: * function only sets x and y values). nkeynes@221: * @return number of vertexes written to the target. nkeynes@221: */ nkeynes@221: static int compute_colour_line( float center_x, float center_y, float center_k, nkeynes@221: int width, int height, float target_k, nkeynes@221: float detxy, float detxk, float detyk, nkeynes@339: struct vertex_unpacked *target ) { nkeynes@221: int num_points = 0; nkeynes@221: float tmpk = (target_k - center_k) * detxy; nkeynes@221: float x0 = -1; nkeynes@221: float x1 = -1; nkeynes@221: nkeynes@221: if( detyk != 0 ) { nkeynes@221: x0 = (tmpk - ((0-center_y)*detxk))/detyk + center_x; /* x where y=0 */ nkeynes@221: if( x0 >= 0.0 && x0 <= width ) { nkeynes@221: target[num_points].x = x0; nkeynes@221: target[num_points].y = 0.0; nkeynes@221: num_points++; nkeynes@221: } nkeynes@221: nkeynes@221: x1 = (tmpk - ((height-center_y)*detxk))/detyk + center_x; /* x where y=height */ nkeynes@221: if( x1 >= 0.0 && x1 <= width ) { nkeynes@221: target[num_points].x = x1; nkeynes@221: target[num_points].y = height; nkeynes@221: num_points++; nkeynes@221: } nkeynes@221: } nkeynes@221: nkeynes@221: if( detxk != 0 ) { nkeynes@221: if( x0 != 0.0 && x1 != 0.0 ) { /* If x0 == 0 or x1 == 0, then we already have this one */ nkeynes@221: float y0 = (tmpk - ((0-center_x)*detyk))/detxk + center_y; /* y where x=0 */ nkeynes@221: if( y0 >= 0.0 && y0 <= height ) { nkeynes@221: target[num_points].x = 0.0; nkeynes@221: target[num_points].y = y0; nkeynes@221: num_points++; nkeynes@221: } nkeynes@221: } nkeynes@221: nkeynes@221: if( x0 != width && x1 != width ) { nkeynes@221: float y1 = (tmpk - ((width-center_x)*detyk))/detxk + center_y; /* y where x=width */ nkeynes@221: if( y1 >= 0.0 && y1 <= height ) { nkeynes@221: target[num_points].x = width; nkeynes@221: target[num_points].y = y1; nkeynes@221: num_points++; nkeynes@221: } nkeynes@221: } nkeynes@221: } nkeynes@221: nkeynes@221: if( num_points == 0 || num_points == 2 ) { nkeynes@221: /* 0 = no points - line doesn't pass through the viewport */ nkeynes@221: /* 2 = normal case - got 2 endpoints */ nkeynes@221: return num_points; nkeynes@221: } else { nkeynes@221: ERROR( "compute_colour_line got bad number of points: %d", num_points ); nkeynes@221: return 0; nkeynes@221: } nkeynes@221: } nkeynes@221: nkeynes@221: /** nkeynes@221: * A region describes a portion of the screen, possibly subdivided by a line. nkeynes@221: * if region_left and region_right are -1, this is a terminal region that can nkeynes@221: * be rendered directly. Otherwise region_left and region_right refer two nkeynes@221: * sub-regions that are separated by the line segment vertex1-vertex2. nkeynes@221: */ nkeynes@221: struct bkg_region { nkeynes@221: /* Vertexes marking the line segment that splits this region */ nkeynes@221: int vertex1; nkeynes@221: int vertex2; nkeynes@221: /* Index of the left sub-region */ nkeynes@221: int region_left; nkeynes@221: /* Index of the right sub-region */ nkeynes@221: int region_right; nkeynes@221: }; nkeynes@221: nkeynes@221: /** nkeynes@221: * Convenience structure to bundle together the vertex and region data. nkeynes@221: */ nkeynes@221: struct bkg_scene { nkeynes@221: int num_vertexes; nkeynes@221: int num_regions; nkeynes@339: struct vertex_unpacked vertexes[MAX_VERTEXES]; nkeynes@221: struct bkg_region regions[MAX_REGIONS]; nkeynes@221: }; nkeynes@221: nkeynes@221: /** nkeynes@221: * Constants returned by compute_line_intersection. Note that for these purposes, nkeynes@221: * "Left" means the point(s) result in a negative value in the line equation, while nkeynes@221: * "Right" means the points(s) result in a positive value in the line equation. The nkeynes@221: * exact meaning isn't particularly important though, as long as we're consistent nkeynes@221: * throughout this process nkeynes@221: */ nkeynes@221: #define LINE_COLLINEAR 0 /* The line segments are part of the same line */ nkeynes@221: #define LINE_SIDE_LEFT 1 /* The second line is entirely to the "left" of the first line */ nkeynes@221: #define LINE_SIDE_RIGHT 2 /* The second line is entirely to the "right" of the first line */ nkeynes@221: #define LINE_INTERSECT_FROM_LEFT 3 /* The lines intersect, and (x3,y3) is to the "left" of the first line */ nkeynes@221: #define LINE_INTERSECT_FROM_RIGHT 4 /* The lines intersect, and (x3,y3) is to the "right" of the first line */ nkeynes@221: #define LINE_SKEW 5 /* The line segments neither intersect nor do any of the above apply (should never happen here) */ nkeynes@221: nkeynes@221: /** nkeynes@221: * Compute the intersection of two line segments, where nkeynes@221: * (x1,y1)-(x2,y2) defines the target segment, and nkeynes@221: * (x3,y3)-(x4,y4) defines the line intersecting it. nkeynes@221: * nkeynes@221: * Based off work by Mukesh Prasad (http://www.acm.org/pubs/tog/GraphicsGems/index.html) nkeynes@221: * nkeynes@221: * @return one of the above LINE_* constants nkeynes@221: */ nkeynes@221: static int compute_line_intersection( float x1, float y1, /* First line segment */ nkeynes@221: float x2, float y2, nkeynes@221: float x3, float y3, /* Second line segment */ nkeynes@221: float x4, float y4, nkeynes@221: float *x, float *y ) /* Output value: */ nkeynes@221: { nkeynes@221: float a1, a2, b1, b2, c1, c2; /* Coefficients of line eqns. */ nkeynes@221: float r1, r2, r3, r4; /* test values */ nkeynes@221: float denom; /* Intermediate values */ nkeynes@221: nkeynes@221: /* Compute a1, b1, c1, where line joining points 1 and 2 nkeynes@221: * is "a1 x + b1 y + c1 = 0". nkeynes@221: */ nkeynes@221: nkeynes@221: a1 = y2 - y1; nkeynes@221: b1 = x1 - x2; nkeynes@221: c1 = x2 * y1 - x1 * y2; nkeynes@221: nkeynes@221: /* Compute r3 and r4. */ nkeynes@221: nkeynes@221: r3 = a1 * x3 + b1 * y3 + c1; nkeynes@221: r4 = a1 * x4 + b1 * y4 + c1; nkeynes@221: nkeynes@221: /* Check signs of r3 and r4. If both point 3 and point 4 lie on nkeynes@221: * same side of line 1, the line segments do not intersect. nkeynes@221: */ nkeynes@221: nkeynes@221: if( r3 == 0 && r4 == 0 ) { nkeynes@221: return LINE_COLLINEAR; nkeynes@221: } else if( r3 <= 0 && r4 <= 0 ) { nkeynes@221: return LINE_SIDE_LEFT; nkeynes@221: } else if( r3 >= 0 && r4 >= 0 ) { nkeynes@221: return LINE_SIDE_RIGHT; nkeynes@221: } nkeynes@221: nkeynes@221: /* Compute a2, b2, c2 */ nkeynes@221: nkeynes@221: a2 = y4 - y3; nkeynes@221: b2 = x3 - x4; nkeynes@221: c2 = x4 * y3 - x3 * y4; nkeynes@221: nkeynes@221: /* Compute r1 and r2 */ nkeynes@221: nkeynes@221: r1 = a2 * x1 + b2 * y1 + c2; nkeynes@221: r2 = a2 * x2 + b2 * y2 + c2; nkeynes@221: nkeynes@221: /* Check signs of r1 and r2. If both point 1 and point 2 lie nkeynes@221: * on same side of second line segment, the line segments do nkeynes@221: * not intersect. nkeynes@221: */ nkeynes@221: nkeynes@221: if ( r1 != 0 && r2 != 0 && nkeynes@221: signbit(r1) == signbit(r2) ) { nkeynes@221: return LINE_SKEW; /* Should never happen */ nkeynes@221: } nkeynes@221: nkeynes@221: /* Cmpute intersection point. nkeynes@221: */ nkeynes@221: denom = a1 * b2 - a2 * b1; nkeynes@221: if ( denom == 0 ) nkeynes@221: return LINE_COLLINEAR; /* Should never get to this point either */ nkeynes@221: nkeynes@221: *x = (b1 * c2 - b2 * c1) / denom; nkeynes@221: *y = (a2 * c1 - a1 * c2) / denom; nkeynes@221: nkeynes@221: if( r3 <= 0 && r4 >= 0 ) { nkeynes@221: return LINE_INTERSECT_FROM_LEFT; nkeynes@221: } else { nkeynes@221: return LINE_INTERSECT_FROM_RIGHT; nkeynes@221: } nkeynes@221: } nkeynes@221: nkeynes@221: /** nkeynes@221: * Given a set of vertexes and a line segment to use to split them, generates nkeynes@221: * two sets of vertexes representing the polygon on either side of the line nkeynes@221: * segment. This method preserves the winding direction of the input vertexes. nkeynes@221: */ nkeynes@221: static void compute_subregions( struct bkg_scene *scene, nkeynes@221: int splitv1, int splitv2, nkeynes@221: int *vertex_in, int num_vertex_in, nkeynes@221: int *left_vertex_out, int *num_left_vertex_out, nkeynes@221: int *right_vertex_out, int *num_right_vertex_out ) nkeynes@221: { nkeynes@221: float x1 = scene->vertexes[splitv1].x; nkeynes@221: float y1 = scene->vertexes[splitv1].y; nkeynes@221: float x2 = scene->vertexes[splitv2].x; nkeynes@221: float y2 = scene->vertexes[splitv2].y; nkeynes@221: nkeynes@221: float a1 = y2 - y1; nkeynes@221: float b1 = x1 - x2; nkeynes@221: float c1 = x2 * y1 - x1 * y2; nkeynes@221: int i; nkeynes@221: nkeynes@221: *num_left_vertex_out = 0; nkeynes@221: *num_right_vertex_out = 0; nkeynes@221: int last = 0; nkeynes@221: for( i=0; ivertexes[vertex_in[i]]; nkeynes@221: float r = a1 * vertex->x + b1 * vertex->y + c1; nkeynes@221: if( r <= 0 ) { nkeynes@221: if( last == 1 ) { nkeynes@221: /* cross-point. add the split vertexes */ nkeynes@221: int v1 = vertex_in[i-1]; nkeynes@221: int v2 = vertex_in[i]; nkeynes@221: /* Determine which point is closer to the line. Strictly speaking nkeynes@221: * one of them must be ON the line, but this way allows for floating nkeynes@221: * point inaccuracies. nkeynes@221: */ nkeynes@221: float a2 = scene->vertexes[v2].y - scene->vertexes[v1].y; nkeynes@221: float b2 = scene->vertexes[v1].x - scene->vertexes[v2].x; nkeynes@221: float c2 = scene->vertexes[v2].x * scene->vertexes[v1].y - nkeynes@221: scene->vertexes[v1].x * scene->vertexes[v2].y; nkeynes@221: float r1 = a2 * x1 + b2 * y1 + c2; nkeynes@221: float r2 = a2 * x2 + b2 * y2 + c2; nkeynes@221: if( fabsf(r1) > fabs(r2) ) { nkeynes@221: int tmp = splitv1; nkeynes@221: splitv1 = splitv2; nkeynes@221: splitv2 = tmp; nkeynes@221: } nkeynes@221: right_vertex_out[(*num_right_vertex_out)++] = splitv1; nkeynes@221: right_vertex_out[(*num_right_vertex_out)++] = splitv2; nkeynes@221: left_vertex_out[(*num_left_vertex_out)++] = splitv2; nkeynes@221: left_vertex_out[(*num_left_vertex_out)++] = splitv1; nkeynes@221: last = 2; nkeynes@221: } else if( last != 2 ) { nkeynes@221: last = -1; nkeynes@221: } nkeynes@221: left_vertex_out[(*num_left_vertex_out)++] = vertex_in[i]; nkeynes@221: } else { nkeynes@221: if( last == -1 ) { nkeynes@221: /* cross-point. add the split vertexes */ nkeynes@221: int v1 = vertex_in[i-1]; nkeynes@221: int v2 = vertex_in[i]; nkeynes@221: /* Determine which point is closer to the line. Strictly speaking nkeynes@221: * one of them must be ON the line, but this way allows for floating nkeynes@221: * point inaccuracies. nkeynes@221: */ nkeynes@221: float a2 = scene->vertexes[v2].y - scene->vertexes[v1].y; nkeynes@221: float b2 = scene->vertexes[v1].x - scene->vertexes[v2].x; nkeynes@221: float c2 = scene->vertexes[v2].x * scene->vertexes[v1].y - nkeynes@221: scene->vertexes[v1].x * scene->vertexes[v2].y; nkeynes@221: float r1 = a2 * x1 + b2 * y1 + c2; nkeynes@221: float r2 = a2 * x2 + b2 * y2 + c2; nkeynes@221: if( fabsf(r1) > fabs(r2) ) { nkeynes@221: int tmp = splitv1; nkeynes@221: splitv1 = splitv2; nkeynes@221: splitv2 = tmp; nkeynes@221: } nkeynes@221: left_vertex_out[(*num_left_vertex_out)++] = splitv1; nkeynes@221: left_vertex_out[(*num_left_vertex_out)++] = splitv2; nkeynes@221: right_vertex_out[(*num_right_vertex_out)++] = splitv2; nkeynes@221: right_vertex_out[(*num_right_vertex_out)++] = splitv1; nkeynes@221: last = 2; nkeynes@221: } else if( last != 2 ) { nkeynes@221: last = 1; nkeynes@221: } nkeynes@221: right_vertex_out[(*num_right_vertex_out)++] = vertex_in[i]; nkeynes@221: } nkeynes@221: } nkeynes@221: } nkeynes@221: nkeynes@221: /** nkeynes@221: * Subdivide the region tree by splitting it along a given line. nkeynes@221: * nkeynes@221: * @param scene current bkg scene data nkeynes@221: * @param region current region under examination nkeynes@221: * @param vertex1 first vertex of the new line segment nkeynes@221: * @param vertex2 second vertex of the new line segment nkeynes@221: */ nkeynes@221: static void bkg_region_subdivide( struct bkg_scene *scene, int region, int vertex1, int vertex2 ) { nkeynes@221: struct bkg_region *this_region = &scene->regions[region]; nkeynes@221: nkeynes@221: if( scene->regions[region].region_left == -1 || scene->regions[region].region_right == -1 ) { nkeynes@221: /* Reached the end of the tree. Setup new left+right regions */ nkeynes@221: int i = scene->num_regions; nkeynes@221: scene->regions[i].region_left = scene->regions[i].region_right = -1; nkeynes@221: scene->regions[i+1].region_left = scene->regions[i+1].region_right = -1; nkeynes@221: this_region->region_left = i; nkeynes@221: this_region->region_right = i+1; nkeynes@221: this_region->vertex1 = vertex1; nkeynes@221: this_region->vertex2 = vertex2; nkeynes@221: scene->num_regions += 2; nkeynes@221: } else { nkeynes@221: float x,y; nkeynes@221: int thisv1 = this_region->vertex1; nkeynes@221: int thisv2 = this_region->vertex2; nkeynes@221: int vertex3; nkeynes@221: int status = nkeynes@221: compute_line_intersection( scene->vertexes[thisv1].x, scene->vertexes[thisv1].y, nkeynes@221: scene->vertexes[thisv2].x, scene->vertexes[thisv2].y, nkeynes@221: scene->vertexes[vertex1].x, scene->vertexes[vertex1].y, nkeynes@221: scene->vertexes[vertex2].x, scene->vertexes[vertex2].y, nkeynes@221: &x, &y ); nkeynes@221: switch( status ) { nkeynes@221: case LINE_INTERSECT_FROM_LEFT: nkeynes@221: /* if new line segment intersects our current line segment, nkeynes@221: * subdivide the segment (add a new vertex) and recurse on both nkeynes@221: * sub trees nkeynes@221: */ nkeynes@221: /* Compute split-point vertex */ nkeynes@221: vertex3 = scene->num_vertexes++; nkeynes@221: scene->vertexes[vertex3].x = x; nkeynes@221: scene->vertexes[vertex3].y = y; nkeynes@221: /* Recurse */ nkeynes@221: bkg_region_subdivide( scene, scene->regions[region].region_left, vertex1,vertex3 ); nkeynes@221: bkg_region_subdivide( scene, scene->regions[region].region_right, vertex3, vertex2 ); nkeynes@221: break; nkeynes@221: case LINE_INTERSECT_FROM_RIGHT: nkeynes@221: /* Same except line runs in the opposite direction */ nkeynes@221: vertex3 = scene->num_vertexes++; nkeynes@221: scene->vertexes[vertex3].x = x; nkeynes@221: scene->vertexes[vertex3].y = y; nkeynes@221: /* Recurse */ nkeynes@221: bkg_region_subdivide( scene, scene->regions[region].region_left, vertex2,vertex3 ); nkeynes@221: bkg_region_subdivide( scene, scene->regions[region].region_right, vertex3, vertex1 ); nkeynes@221: break; nkeynes@221: case LINE_COLLINEAR: nkeynes@221: case LINE_SKEW: nkeynes@221: /* Collinear - ignore */ nkeynes@221: break; nkeynes@221: case LINE_SIDE_LEFT: nkeynes@221: /* else if line segment passes through the left sub-region alone, nkeynes@221: * left-recurse only. nkeynes@221: */ nkeynes@221: bkg_region_subdivide( scene, scene->regions[region].region_left, vertex1, vertex2 ); nkeynes@221: break; nkeynes@221: case LINE_SIDE_RIGHT: nkeynes@221: /* Otherwise line segment passes through the right sub-region alone, nkeynes@221: * so right-recurse. nkeynes@221: */ nkeynes@221: bkg_region_subdivide( scene, scene->regions[region].region_right, vertex1, vertex2 ); nkeynes@221: break; nkeynes@221: } nkeynes@221: } nkeynes@221: } nkeynes@221: nkeynes@221: nkeynes@221: nkeynes@221: /** nkeynes@219: * Compute the values for an array of vertexes, given x,y for each nkeynes@219: * vertex and the base 3-vertex triple used to define the background nkeynes@219: * plane. Essentially the base vertexes are used to find the nkeynes@219: * plane equation for each of z,a,r,g,b,etc, which is then solved for nkeynes@219: * each of the required compute vertexes (normally the corner points). nkeynes@219: * nkeynes@219: * @param base The 3 vertexes supplied as the background definition nkeynes@219: * @param compute An array of vertexes to compute. x and y must be nkeynes@219: * preset, other values are computed. nkeynes@219: */ nkeynes@339: static void bkg_compute_scene( struct vertex_unpacked *base, int width, int height, nkeynes@221: struct bkg_scene *scene ) nkeynes@219: { nkeynes@339: struct vertex_unpacked center; nkeynes@339: struct vertex_unpacked diff0, diff1; nkeynes@221: int i,k; nkeynes@219: nkeynes@219: center.x = base[1].x; nkeynes@219: center.y = base[1].y; nkeynes@339: center.z = (1/base[1].z); nkeynes@429: center.u = base[1].u; nkeynes@429: center.v = base[1].v; nkeynes@339: diff0.x = base[0].x - center.x; nkeynes@339: diff0.y = base[0].y - center.y; nkeynes@339: diff0.z = (1/base[0].z) - center.z; nkeynes@339: diff1.x = base[2].x - center.x; nkeynes@339: diff1.y = base[2].y - center.y; nkeynes@339: diff1.z = (1/base[2].z) - center.z; nkeynes@219: nkeynes@221: float detxy = ((diff1.y) * (diff0.x)) - ((diff0.y) * (diff1.x)); nkeynes@221: nkeynes@221: /* Corner points first */ nkeynes@221: scene->vertexes[0].x = 0.0; nkeynes@221: scene->vertexes[0].y = 0.0; nkeynes@221: scene->vertexes[1].x = width; nkeynes@221: scene->vertexes[1].y = 0.0; nkeynes@221: scene->vertexes[2].x = width; nkeynes@221: scene->vertexes[2].y = height; nkeynes@221: scene->vertexes[3].x = 0.0; nkeynes@221: scene->vertexes[3].y = height; nkeynes@221: scene->regions[0].region_left = -1; nkeynes@221: scene->regions[0].region_right = -1; nkeynes@221: scene->num_vertexes = 4; nkeynes@221: scene->num_regions = 1; nkeynes@221: nkeynes@221: if( detxy == 0 ) { nkeynes@221: /* The points lie on a single line - no plane for you. Use the values nkeynes@221: * from the 3rd point for the whole screen. nkeynes@221: */ nkeynes@221: for( i=0; i<4; i++ ) { nkeynes@221: scene->vertexes[i].rgba[0] = base[2].rgba[0]; nkeynes@221: scene->vertexes[i].rgba[1] = base[2].rgba[1]; nkeynes@221: scene->vertexes[i].rgba[2] = base[2].rgba[2]; nkeynes@221: scene->vertexes[i].rgba[3] = base[2].rgba[3]; nkeynes@339: scene->vertexes[i].z = 1/base[2].z; nkeynes@221: scene->vertexes[i].u = base[2].u; nkeynes@221: scene->vertexes[i].v = base[2].v; nkeynes@221: } nkeynes@219: } else { nkeynes@221: /* Compute the colour values at each corner */ nkeynes@221: center.rgba[0] = base[1].rgba[0]; nkeynes@221: center.rgba[1] = base[1].rgba[1]; nkeynes@221: center.rgba[2] = base[1].rgba[2]; nkeynes@221: center.rgba[3] = base[1].rgba[3]; nkeynes@221: diff0.rgba[0] = base[0].rgba[0] - center.rgba[0]; nkeynes@221: diff0.rgba[1] = base[0].rgba[1] - center.rgba[1]; nkeynes@221: diff0.rgba[2] = base[0].rgba[2] - center.rgba[2]; nkeynes@221: diff0.rgba[3] = base[0].rgba[3] - center.rgba[3]; nkeynes@221: diff0.u = base[0].u - center.u; nkeynes@221: diff0.v = base[0].v - center.v; nkeynes@221: diff1.rgba[0] = base[2].rgba[0] - center.rgba[0]; nkeynes@221: diff1.rgba[1] = base[2].rgba[1] - center.rgba[1]; nkeynes@221: diff1.rgba[2] = base[2].rgba[2] - center.rgba[2]; nkeynes@221: diff1.rgba[3] = base[2].rgba[3] - center.rgba[3]; nkeynes@221: diff1.u = base[2].u - center.u; nkeynes@221: diff1.v = base[2].v - center.v; nkeynes@221: for( i=0; i<4; i++ ) { nkeynes@221: float t = ((scene->vertexes[i].x - center.x) * diff1.y - nkeynes@221: (scene->vertexes[i].y - center.y) * diff1.x) / detxy; nkeynes@221: float s = ((scene->vertexes[i].y - center.y) * diff0.x - nkeynes@221: (scene->vertexes[i].x - center.x) * diff0.y) / detxy; nkeynes@221: scene->vertexes[i].z = center.z + (t*diff0.z) + (s*diff1.z); nkeynes@221: scene->vertexes[i].rgba[0] = center.rgba[0] + (t*diff0.rgba[0]) + (s*diff1.rgba[0]); nkeynes@221: scene->vertexes[i].rgba[1] = center.rgba[1] + (t*diff0.rgba[1]) + (s*diff1.rgba[1]); nkeynes@221: scene->vertexes[i].rgba[2] = center.rgba[2] + (t*diff0.rgba[2]) + (s*diff1.rgba[2]); nkeynes@221: scene->vertexes[i].rgba[3] = center.rgba[3] + (t*diff0.rgba[3]) + (s*diff1.rgba[3]); nkeynes@221: scene->vertexes[i].u = center.u + (t*diff0.u) + (s*diff1.u); nkeynes@221: scene->vertexes[i].v = center.v + (t*diff0.v) + (s*diff1.v); nkeynes@221: } nkeynes@221: nkeynes@221: /* Check for values > 1.0 | < 0.0 */ nkeynes@221: for( k=0; k<4; k++ ) { nkeynes@221: float detyk = ((diff1.y) * (diff0.rgba[k])) - ((diff0.y)*(diff1.rgba[k])); nkeynes@221: float detxk = ((diff0.x) * (diff1.rgba[k])) - ((diff1.x)*(diff0.rgba[k])); nkeynes@221: if( scene->vertexes[0].rgba[k] > 1.0 || scene->vertexes[1].rgba[k] > 1.0 || nkeynes@221: scene->vertexes[2].rgba[k] > 1.0 || scene->vertexes[3].rgba[k] > 1.0 ) { nkeynes@221: int v1 = scene->num_vertexes; nkeynes@221: scene->num_vertexes += compute_colour_line(center.x, center.y, center.rgba[k], nkeynes@221: width, height, 1.0, nkeynes@221: detxy, detxk, detyk, nkeynes@221: scene->vertexes+scene->num_vertexes ); nkeynes@221: if( scene->num_vertexes != v1 ) { nkeynes@221: bkg_region_subdivide( scene, 0, v1, v1+1 ); nkeynes@221: } nkeynes@221: } nkeynes@221: nkeynes@221: if( scene->vertexes[0].rgba[k] < 0.0 || scene->vertexes[1].rgba[k] < 0.0 || nkeynes@221: scene->vertexes[2].rgba[k] < 0.0 || scene->vertexes[3].rgba[k] < 0.0 ) { nkeynes@221: int v1 = scene->num_vertexes; nkeynes@221: scene->num_vertexes += compute_colour_line(center.x, center.y, center.rgba[k], nkeynes@221: width, height, 0.0, nkeynes@221: detxy, detxk, detyk, nkeynes@221: scene->vertexes+scene->num_vertexes ); nkeynes@221: if( scene->num_vertexes != v1 ) { nkeynes@221: bkg_region_subdivide( scene, 0, v1, v1+1 ); nkeynes@221: } nkeynes@221: nkeynes@221: } nkeynes@221: } nkeynes@221: nkeynes@221: /* Finally compute the colour values for all vertexes nkeynes@221: * (excluding the 4 we did upfront) */ nkeynes@221: for( i=4; inum_vertexes; i++ ) { nkeynes@221: float t = ((scene->vertexes[i].x - center.x) * diff1.y - nkeynes@221: (scene->vertexes[i].y - center.y) * diff1.x) / detxy; nkeynes@221: float s = ((scene->vertexes[i].y - center.y) * diff0.x - nkeynes@221: (scene->vertexes[i].x - center.x) * diff0.y) / detxy; nkeynes@221: scene->vertexes[i].z = center.z + (t*diff0.z) + (s*diff1.z); nkeynes@221: scene->vertexes[i].rgba[0] = center.rgba[0] + (t*diff0.rgba[0]) + (s*diff1.rgba[0]); nkeynes@221: scene->vertexes[i].rgba[1] = center.rgba[1] + (t*diff0.rgba[1]) + (s*diff1.rgba[1]); nkeynes@221: scene->vertexes[i].rgba[2] = center.rgba[2] + (t*diff0.rgba[2]) + (s*diff1.rgba[2]); nkeynes@221: scene->vertexes[i].rgba[3] = center.rgba[3] + (t*diff0.rgba[3]) + (s*diff1.rgba[3]); nkeynes@221: scene->vertexes[i].u = center.u + (t*diff0.u) + (s*diff1.u); nkeynes@221: scene->vertexes[i].v = center.v + (t*diff0.v) + (s*diff1.v); nkeynes@219: } nkeynes@219: } nkeynes@219: } nkeynes@219: nkeynes@221: /** nkeynes@221: * Render a bkg_region. nkeynes@221: * @param scene the background scene data nkeynes@221: * @param region the region to render nkeynes@221: * @param vertexes the vertexes surrounding the region nkeynes@221: * @param num_vertexes the number of vertexes in the vertex array nkeynes@221: */ nkeynes@221: void bkg_render_region( struct bkg_scene *scene, int region, int *vertexes, int num_vertexes, nkeynes@221: uint32_t poly1 ) nkeynes@221: { nkeynes@221: if( scene->regions[region].region_left == -1 && scene->regions[region].region_right == -1 ) { nkeynes@221: /* Leaf node - render the points as given */ nkeynes@221: int i,k; nkeynes@221: glBegin(GL_POLYGON); nkeynes@221: for( i=0; ivertexes[k].rgba); nkeynes@221: if( POLY1_TEXTURED(poly1) ) { nkeynes@221: glTexCoord2f(scene->vertexes[k].u, scene->vertexes[k].v); nkeynes@221: } nkeynes@221: glVertex3f(scene->vertexes[k].x, scene->vertexes[k].y, scene->vertexes[k].z); nkeynes@221: } nkeynes@221: glEnd(); nkeynes@221: } else { nkeynes@221: /* split the region into left and right regions */ nkeynes@221: int left_vertexes[num_vertexes+1]; nkeynes@221: int right_vertexes[num_vertexes+1]; nkeynes@221: int num_left = 0; nkeynes@221: int num_right = 0; nkeynes@221: struct bkg_region *reg = &scene->regions[region]; nkeynes@221: compute_subregions( scene, reg->vertex1, reg->vertex2, vertexes, num_vertexes, nkeynes@221: left_vertexes, &num_left, right_vertexes, &num_right ); nkeynes@221: bkg_render_region( scene, reg->region_left, left_vertexes, num_left, poly1 ); nkeynes@221: bkg_render_region( scene, reg->region_right, right_vertexes, num_right, poly1 ); nkeynes@221: } nkeynes@221: nkeynes@221: } nkeynes@221: nkeynes@221: nkeynes@219: void render_backplane( uint32_t *polygon, uint32_t width, uint32_t height, uint32_t mode ) { nkeynes@339: struct vertex_unpacked vertex[3]; nkeynes@221: int screen_vertexes[4] = {0,1,2,3}; nkeynes@221: struct bkg_scene scene; nkeynes@339: int vertex_length = (mode >> 24) & 0x07; nkeynes@339: int cheap_shadow = MMIO_READ( PVR2, RENDER_SHADOW ) & 0x100; nkeynes@339: int is_modified = mode & 0x08000000; nkeynes@339: int context_length = 3; nkeynes@339: if( is_modified && !cheap_shadow ) { nkeynes@339: context_length = 5; nkeynes@339: vertex_length *= 2; nkeynes@339: } nkeynes@339: vertex_length += 3; nkeynes@339: context_length += (mode & 0x07) * vertex_length; nkeynes@339: nkeynes@219: nkeynes@339: render_unpack_vertexes( vertex, *polygon, polygon+context_length, 3, vertex_length, nkeynes@339: RENDER_NORMAL ); nkeynes@339: bkg_compute_scene(vertex, width, height, &scene); nkeynes@339: render_set_context(polygon, RENDER_NORMAL); nkeynes@221: glDisable(GL_CULL_FACE); nkeynes@221: glDisable(GL_DEPTH_TEST); nkeynes@221: glBlendFunc(GL_ONE, GL_ZERO); /* For now, just disable alpha blending on the bkg */ nkeynes@221: bkg_render_region(&scene, 0, screen_vertexes, 4, *polygon); nkeynes@219: }