/* Copyright (C) 2002-2003 Charles Hollemeersch This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. PENTA: Bezier curve code... We evaluate curves at load time based on the user's precision preferences. No dynamic lod... */ #include "quakedef.h" int numleafbrushes; mcurve_t *curvechain = NULL; #define MAX_BIN 10 int binomials[MAX_BIN][MAX_BIN]; /* We roll or own Bezier code... Dunno how id is supposed to do it but we just evaluate the Bernstein polynomials.... It's not particulary efficient but we pre-evaluate them so it's not a problem... */ int fac(int n) { int i; int rez = 1; for (i=2;i<=n;i++) { rez*=i; } return rez; } int binomial(int n, int k) { return fac(n)/fac(k)/fac(n-k); } //Make a lookup table ... void CS_FillBinomials(void) { int i,j; for (i=0; iposition[i] = 0.0; } for (i=0; i<2; i++) { result->texture[i] = 0.0; result->lightmap[i] = 0.0; } for (i=0; iposition[0]+=(scale*controlpoint->position[0]); result->position[1]+=(scale*controlpoint->position[1]); result->position[2]+=(scale*controlpoint->position[2]); result->texture[0]+=(scale*controlpoint->texture[0]); result->texture[1]+=(scale*controlpoint->texture[1]); result->lightmap[0]+=(scale*controlpoint->lightmap[0]); result->lightmap[1]+=(scale*controlpoint->lightmap[1]); color[0]+=(scale*controlpoint->color[0]); color[1]+=(scale*controlpoint->color[1]); color[2]+=(scale*controlpoint->color[2]); color[3]+=(scale*controlpoint->color[3]); } } for (i=0; i<4; i++) { result->color[i] = (byte)color[i]; } } void EvaluateBiquadraticBeziers(mmvertex_t *controlpoints, int width, int height, float u, float v,mmvertex_t *result) { // EvaluateBezier(controlpoints,0,0,width,height,u,v,result); //calculate number of patches in curve int numpatchx = (width- 1) / 2; int numpatchy = (height- 1) / 2; float invx = 1.0f / numpatchx; float invy = 1.0f / numpatchy; //caclucate patch given u/v is on int ofsx = floor(u*numpatchx)*2; int ofsy = floor(v*numpatchy)*2; if (ofsx >= (width-1)) ofsx-=2; if (ofsy >= (height-1)) ofsy-=2; //calculate u/v relative to patch u = (u-(ofsx/2)*invx)*numpatchx; v = (v-(ofsy/2)*invy)*numpatchy; EvaluateBezier(controlpoints,ofsx,ofsy,width,height,u,v,result); } void MeanVert( mmvertex_t *a, mmvertex_t *b, mmvertex_t *out ) { out->position[0] = 0.5 * (a->position[0] + b->position[0]); out->position[1] = 0.5 * (a->position[1] + b->position[1]); out->position[2] = 0.5 * (a->position[2] + b->position[2]); out->texture[0] = 0.5 * (a->texture[0] + b->texture[0]); out->texture[1] = 0.5 * (a->texture[1] + b->texture[1]); out->lightmap[0] = 0.5 * (a->lightmap[0] + b->lightmap[0]); out->lightmap[1] = 0.5 * (a->lightmap[1] + b->lightmap[1]); out->color[0] = (a->color[0] + b->color[0]) >> 1; out->color[1] = (a->color[1] + b->color[1]) >> 1; out->color[2] = (a->color[2] + b->color[2]) >> 1; out->color[3] = (a->color[3] + b->color[3]) >> 1; } /* ================= PutMeshOnCurve Drops the aproximating points onto the curve ================= */ void PutMeshOnCurve(mcurve_t in, mmvertex_t *verts) { int i, j, l, w, h; float prev, next; float du, dv, u ,v; mmvertex_t results[128*128]; du = 1.0f/(in.width-1); dv = 1.0f/(in.height-1); for (i=0, u=0; icontrolwidth*amount; newheight = in->controlheight*amount; du = 1.0f/(newwidth-1); dv = 1.0f/(newheight-1); for (i=0, u=0; icontrolwidth,in->controlheight,u,v,&expand[i+j*newwidth]); } } for (i=0; ifirstvertex = R_AllocateVertexInTemp(expand[i].position, expand[i].texture, expand[i].lightmap, expand[i].color); else R_AllocateVertexInTemp(expand[i].position, expand[i].texture, expand[i].lightmap, expand[i].color); } in->width = newwidth; in->height = newheight; } #define MAX_EXPANDED_AXIS 128 int originalWidths[MAX_EXPANDED_AXIS]; int originalHeights[MAX_EXPANDED_AXIS]; /* ================= SubdivideMesh ================= */ /* void SubdivideMesh(mcurve_t *in, float maxError, float minLength, mmvertex_t *verts) { int i, j, k, l; mmvertex_t prev, next, mid; vec3_t prevposition, nextposition, midposition; vec3_t delta; float len; mmvertex_t expand[MAX_EXPANDED_AXIS][MAX_EXPANDED_AXIS]; for ( i = 0 ; i < in->width ; i++ ) { for ( j = 0 ; j < in->height ; j++ ) { expand[j][i] = verts[j*in->width+i]; } } for ( i = 0 ; i < in->height ; i++ ) { originalHeights[i] = i; } for ( i = 0 ; i < in->width ; i++ ) { originalWidths[i] = i; } // horizontal subdivisions for ( j = 0 ; j + 2 < in->width ; j += 2 ) { // check subdivided midpoints against control points for ( i = 0 ; i < in->height ; i++ ) { for ( l = 0 ; l < 3 ; l++ ) { prevposition[l] = expand[i][j+1].position[l] - expand[i][j].position[l]; nextposition[l] = expand[i][j+2].position[l] - expand[i][j+1].position[l]; midposition[l] = (expand[i][j].position[l] + expand[i][j+1].position[l] * 2 + expand[i][j+2].position[l] ) * 0.25; } // if the span length is too long, force a subdivision if ( Length( prevposition ) > minLength || Length( nextposition ) > minLength ) { break; } // see if this midpoint is off far enough to subdivide VectorSubtract( expand[i][j+1].position, midposition, delta ); len = Length( delta ); if ( len > maxError ) { break; } } if ( in->width + 2 >= MAX_EXPANDED_AXIS ) { break; // can't subdivide any more } if ( i == in->height ) { continue; // didn't need subdivision } // insert two columns and replace the peak in->width += 2; for ( k = in->width - 1 ; k > j + 3 ; k-- ) { originalWidths[k] = originalWidths[k-2]; } originalWidths[j+3] = originalWidths[j+1]; originalWidths[j+2] = originalWidths[j+1]; originalWidths[j+1] = originalWidths[j]; for ( i = 0 ; i < in->height ; i++ ) { MeanVert( &expand[i][j], &expand[i][j+1], &prev ); MeanVert( &expand[i][j+1], &expand[i][j+2], &next ); MeanVert( &prev, &next, &mid ); for ( k = in->width - 1 ; k > j + 3 ; k-- ) { expand[i][k] = expand[i][k-2]; } expand[i][j + 1] = prev; expand[i][j + 2] = mid; expand[i][j + 3] = next; } // back up and recheck this set again, it may need more subdivision j -= 2; } // vertical subdivisions for ( j = 0 ; j + 2 < in->height ; j += 2 ) { // check subdivided midpoints against control points for ( i = 0 ; i < in->width ; i++ ) { for ( l = 0 ; l < 3 ; l++ ) { prevposition[l] = expand[j+1][i].position[l] - expand[j][i].position[l]; nextposition[l] = expand[j+2][i].position[l] - expand[j+1][i].position[l]; midposition[l] = (expand[j][i].position[l] + expand[j+1][i].position[l] * 2 + expand[j+2][i].position[l] ) * 0.25; } // if the span length is too long, force a subdivision if ( Length( prevposition ) > minLength || Length( nextposition ) > minLength ) { break; } // see if this midpoint is off far enough to subdivide VectorSubtract( expand[j+1][i].position, midposition, delta ); len = Length( delta ); if ( len > maxError ) { break; } } if ( in->height + 2 >= MAX_EXPANDED_AXIS ) { break; // can't subdivide any more } if ( i == in->width ) { continue; // didn't need subdivision } // insert two columns and replace the peak in->height += 2; for ( k = in->height - 1 ; k > j + 3 ; k-- ) { originalHeights[k] = originalHeights[k-2]; } originalHeights[j+3] = originalHeights[j+1]; originalHeights[j+2] = originalHeights[j+1]; originalHeights[j+1] = originalHeights[j]; for ( i = 0 ; i < in->width ; i++ ) { MeanVert( &expand[j][i], &expand[j+1][i], &prev ); MeanVert( &expand[j+1][i], &expand[j+2][i], &next ); MeanVert( &prev, &next, &mid ); for ( k = in->height - 1 ; k > j + 3 ; k-- ) { expand[k][i] = expand[k-2][i]; } expand[j+1][i] = prev; expand[j+2][i] = mid; expand[j+3][i] = next; } // back up and recheck this set again, it may need more subdivision j -= 2; } // collapse the verts verts = &expand[0][0]; for ( i = 1 ; i < in->height ; i++ ) { memmove( &verts[i*in->width], expand[i], in->width * sizeof(mmvertex_t) ); } for (i=0; iwidth; i++) { for (j=0; jheight; j++) { if ((i==0) && (j==0)) in->firstcontrol = R_AllocateVertexInTemp(expand[j][i].position, expand[j][i].texture, expand[j][i].lightmap, expand[j][i].color); else R_AllocateVertexInTemp(expand[j][i].position, expand[j][i].texture, expand[j][i].lightmap, expand[j][i].color); } } */ /* out.verts = &expand[0][0]; for ( i = 1 ; i < out.height ; i++ ) { memmove( &out.verts[i*out.width], expand[i], out.width * sizeof(drawVert_t) ); } return CopyMesh(&out); */ //} /* ================= CurveCreate Creates a curve from the given surface ================= */ void CS_Create(dq3face_t *in, mcurve_t *curve, texture_t *texture) { curve->controlwidth = in->patchOrder[0]; curve->controlheight = in->patchOrder[1]; curve->firstcontrol = in->firstvertex; //just use the control points as vertices curve->firstvertex = in->firstmeshvertex; curve->width = curve->controlwidth; curve->height = curve->controlheight; curve->next = NULL; curve->texture = texture; if (gl_mesherror.value > 0) SubdivideCurve(curve,&tempVertices[curve->firstcontrol],gl_mesherror.value); //PutMeshOnCurve(*curve,&tempVertices[curve->firstcontrol]); //SubdivideMesh(curve,gl_mesherror.value,1000,&tempVertices[curve->firstcontrol]); // Con_Printf("MeshCurve %i %i %i\n",curve->firstcontrol,curve->controlwidth,curve->controlheight); } void CS_DrawAmbient(mcurve_t *curve) { int i,j, i1, i2; int w,h; GL_Bind(curve->texture->gl_texturenum); glShadeModel (GL_SMOOTH); //Con_Printf("Drawcurve %i %i %i\n",curve->firstvertex,curve->width,curve->height); h = curve->width; w = curve->height; for (i=0; ifirstvertex+j+(i+1)*h; i2 = curve->firstvertex+j+i*h; glColor3ubv((byte *)&((float *)&globalVertexTable[i2])[7]); glTexCoord2fv(&((float *)&globalVertexTable[i2])[3]); glVertex3fv((float *)&globalVertexTable[i2]); glColor3ubv((byte *)&((float *)&globalVertexTable[i1])[7]); glTexCoord2fv(&((float *)&globalVertexTable[i1])[3]); glVertex3fv((float *)&globalVertexTable[i1]); } glEnd(); } }