/* * @brief */ static void FinishSubdividePatch(patch_t *patch, patch_t *newp) { VectorCopy(patch->normal, newp->normal); VectorCopy(patch->light, newp->light); patch->area = WindingArea(patch->winding); if (patch->area < 1.0) patch->area = 1.0; newp->area = WindingArea(newp->winding); if (newp->area < 1.0) newp->area = 1.0; WindingCenter(patch->winding, patch->origin); // nudge the patch origin out along the normal VectorMA(patch->origin, 2.0, patch->normal, patch->origin); WindingCenter(newp->winding, newp->origin); // nudge the patch origin out along the normal VectorMA(newp->origin, 2.0, newp->normal, newp->origin); }
void MarkLeakTrail (portal_t *n2) { int i, j; vec3_t p1, p2, dir; float len; portal_t *n1; if (hullnum) return; n1 = prevleaknode; prevleaknode = n2; if (!n1) return; WindingCenter (n2->winding, p1); WindingCenter (n1->winding, p2); fprintf (linefile, "%f %f %f\n", p1[0], p1[1], p1[2]); VectorSubtract (p2, p1, dir); len = VectorLength (dir); VectorNormalize (dir); while (len > 2) { fprintf (pointfile,"%f %f %f\n", p1[0], p1[1], p1[2]); for (i=0 ; i<3 ; i++) p1[i] += dir[i]*2; len -= 2; } }
void FinishSplit( patch_t *patch, patch_t *newp ){ dleaf_t *leaf; VectorCopy( patch->baselight, newp->baselight ); VectorCopy( patch->totallight, newp->totallight ); VectorCopy( patch->reflectivity, newp->reflectivity ); newp->plane = patch->plane; newp->sky = patch->sky; patch->area = WindingArea( patch->winding ); newp->area = WindingArea( newp->winding ); if ( patch->area <= 1 ) { patch->area = 1; } if ( newp->area <= 1 ) { newp->area = 1; } WindingCenter( patch->winding, patch->origin ); VectorAdd( patch->origin, patch->plane->normal, patch->origin ); leaf = Rad_PointInLeaf( patch->origin ); patch->cluster = leaf->cluster; if ( patch->cluster == -1 ) { Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n" ); } WindingCenter( newp->winding, newp->origin ); VectorAdd( newp->origin, newp->plane->normal, newp->origin ); leaf = Rad_PointInLeaf( newp->origin ); newp->cluster = leaf->cluster; if ( newp->cluster == -1 ) { Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n" ); } }
/* * @brief */ static void BuildPatch(int32_t fn, winding_t *w) { patch_t *patch; d_bsp_plane_t *plane; patch = (patch_t *) Mem_Malloc(sizeof(*patch)); face_patches[fn] = patch; patch->face = &d_bsp.faces[fn]; patch->winding = w; // resolve the normal plane = &d_bsp.planes[patch->face->plane_num]; if (patch->face->side) VectorNegate(plane->normal, patch->normal); else VectorCopy(plane->normal, patch->normal); WindingCenter(w, patch->origin); // nudge the origin out along the normal VectorMA(patch->origin, 2.0, patch->normal, patch->origin); patch->area = WindingArea(w); if (patch->area < 1.0) // clamp area patch->area = 1.0; EmissiveLight(patch); // surface light }
/** * @brief Build a patch for a surface that emits light * @note This is called in the lighting stage * @param fn The face number of the surface that emits the light * @param w The winding * @sa BuildLights */ static void BuildPatch (int fn, winding_t* w) { patch_t* patch; dBspPlane_t* plane; patch = Mem_AllocType(patch_t); face_patches[fn] = patch; patch->face = &curTile->faces[fn]; patch->winding = w; /* resolve the normal */ plane = &curTile->planes[patch->face->planenum]; if (patch->face->side) VectorNegate(plane->normal, patch->normal); else VectorCopy(plane->normal, patch->normal); WindingCenter(w, patch->origin); /* nudge the origin out along the normal */ VectorMA(patch->origin, 2.0, patch->normal, patch->origin); patch->area = WindingArea(w); if (patch->area < 1.0) /* clamp area */ patch->area = 1.0; EmissiveLight(patch); /* surface light */ }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_FlipAreaFaces(tmp_area_t *tmparea) { int side; tmp_face_t *face; plane_t *plane; vec3_t wcenter, acenter = {0, 0, 0}; //winding_t *w; float n; for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side]) { if (!face->frontarea) Error("face %d has no front area\n", face->num); //side of the face the area is on side = face->frontarea != tmparea; WindingCenter(face->winding, wcenter); VectorAdd(acenter, wcenter, acenter); n++; } //end for n = 1 / n; VectorScale(acenter, n, acenter); for (face = tmparea->tmpfaces; face; face = face->next[side]) { //side of the face the area is on side = face->frontarea != tmparea; plane = &mapplanes[face->planenum ^ side]; if (DotProduct(plane->normal, acenter) - plane->dist < 0) { Log_Print("area %d face %d flipped: front area %d, back area %d\n", tmparea->areanum, face->num, face->frontarea ? face->frontarea->areanum : 0, face->backarea ? face->backarea->areanum : 0); /* face->planenum = face->planenum ^ 1; w = face->winding; face->winding = ReverseWinding(w); FreeWinding(w); */ } //end if #ifdef L_DEBUG { float dist; vec3_t normal; //check if the winding plane is the same as the face plane WindingPlane(face->winding, normal, &dist); plane = &mapplanes[face->planenum]; if (fabs(dist - plane->dist) > 0.4 || fabs(normal[0] - plane->normal[0]) > 0.0001 || fabs(normal[1] - plane->normal[1]) > 0.0001 || fabs(normal[2] - plane->normal[2]) > 0.0001) { Log_Write("area %d face %d winding plane unequal to face plane\r\n", tmparea->areanum, face->num); } //end if } #endif } //end for } //end of the function AAS_FlipAreaFaces
/* ============= LeakFile Finds the shortest possible chain of portals that leads from the outside leaf to a specifically occupied leaf ============= */ void LeakFile (tree_t *tree) { vec3_t mid; FILE *linefile; char filename[1024]; node_t *node; int count; if (!tree->outside_node.occupied) return; qprintf ("--- LeakFile ---\n"); // // write the points to the file // sprintf (filename, "%s.lin", source); qprintf ("%s\n", filename); linefile = fopen (filename, "w"); if (!linefile) Error ("Couldn't open %s\n", filename); count = 0; node = &tree->outside_node; while (node->occupied > 1) { int next; portal_t *p, *nextportal; node_t *nextnode; int s; // find the best portal exit next = node->occupied; for (p=node->portals ; p ; p = p->next[!s]) { s = (p->nodes[0] == node); if (p->nodes[s]->occupied && p->nodes[s]->occupied < next) { nextportal = p; nextnode = p->nodes[s]; next = nextnode->occupied; } } node = nextnode; WindingCenter (nextportal->winding, mid); fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); count++; } // add the occupant center GetVectorForKey (node->occupant, "origin", mid); fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); qprintf ("%5i point linefile\n", count+1); fclose (linefile); }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_CheckArea(tmp_area_t *tmparea) { int side; tmp_face_t *face; plane_t *plane; vec3_t wcenter, acenter = {0, 0, 0}; vec3_t normal; float n, dist; if (tmparea->invalid) Log_Print("AAS_CheckArea: invalid area\n"); for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side]) { //side of the face the area is on side = face->frontarea != tmparea; WindingCenter(face->winding, wcenter); VectorAdd(acenter, wcenter, acenter); n++; } //end for n = 1 / n; VectorScale(acenter, n, acenter); for (face = tmparea->tmpfaces; face; face = face->next[side]) { //side of the face the area is on side = face->frontarea != tmparea; #ifdef L_DEBUG if (WindingError(face->winding)) { Log_Write("AAS_CheckArea: area %d face %d: %s\r\n", tmparea->areanum, face->num, WindingErrorString()); } //end if #endif plane = &mapplanes[face->planenum ^ side]; if (DotProduct(plane->normal, acenter) - plane->dist < 0) { Log_Print("AAS_CheckArea: area %d face %d is flipped\n", tmparea->areanum, face->num); Log_Print("AAS_CheckArea: area %d center is %f %f %f\n", tmparea->areanum, acenter[0], acenter[1], acenter[2]); } //end if //check if the winding plane is the same as the face plane WindingPlane(face->winding, normal, &dist); plane = &mapplanes[face->planenum]; #ifdef L_DEBUG if (fabs(dist - plane->dist) > 0.4 || fabs(normal[0] - plane->normal[0]) > 0.0001 || fabs(normal[1] - plane->normal[1]) > 0.0001 || fabs(normal[2] - plane->normal[2]) > 0.0001) { Log_Write("AAS_CheckArea: area %d face %d winding plane unequal to face plane\r\n", tmparea->areanum, face->num); } //end if #endif } //end for } //end of the function AAS_CheckArea
//----------------------------------------------------------------------------- // Display portal error //----------------------------------------------------------------------------- static void DisplayPortalError( portal_t *p, int viscontents ) { char contents[3][1024]; PrintBrushContentsToString( p->nodes[0]->contents, contents[0], sizeof( contents[0] ) ); PrintBrushContentsToString( p->nodes[1]->contents, contents[1], sizeof( contents[1] ) ); PrintBrushContentsToString( viscontents, contents[2], sizeof( contents[2] ) ); Vector center; WindingCenter( p->winding, center ); Warning( "\nFindPortalSide: Couldn't find a good match for which brush to assign to a portal near (%.1f %.1f %.1f)\n", center.x, center.y, center.z); Warning( "Leaf 0 contents: %s\n", contents[0] ); Warning( "Leaf 1 contents: %s\n", contents[1] ); Warning( "viscontents (node 0 contents ^ node 1 contents): %s\n", contents[2] ); Warning( "This means that none of the brushes in leaf 0 or 1 that touches the portal has %s\n", contents[2] ); Warning( "Check for a huge brush enclosing the coordinates above that has contents %s\n", contents[2] ); Warning( "Candidate brush IDs: " ); CUtlVector<int> listed; for (int j=0 ; j<2 ; j++) { node_t *n = p->nodes[j]; for (bspbrush_t *bb=n->brushlist ; bb ; bb=bb->next) { mapbrush_t *brush = bb->original; if ( brush->contents & viscontents ) { if ( listed.Find( brush->brushnum ) == -1 ) { listed.AddToTail( brush->brushnum ); Warning( "Brush %d: ", brush->id ); } } } } Warning( "\n\n" ); }
//----------------------------------------------------------------------------- // Purpose: Recursively filter a face into the tree leaving references to the // original face in any visible leaves that a clipped fragment falls // into. // Input : *node - current head of tree // *face - clipped face fragment // *original - unclipped original face // Output : Returns true if any references were left //----------------------------------------------------------------------------- bool MergeFace_r( node_t *node, face_t *face, face_t *original ) { bool referenced = false; if ( node->planenum == PLANENUM_LEAF ) { if ( node->contents & CONTENTS_SOLID ) { FreeFace( face ); return false; } leafface_t *plist = new leafface_t; plist->pFace = original; plist->pNext = node->leaffacelist; node->leaffacelist = plist; referenced = true; } else { // UNDONE: Don't copy the faces each time unless it's necessary!?!?! plane_t *plane = &g_MainMap->mapplanes[node->planenum]; winding_t *frontwinding, *backwinding, *onwinding; Vector offset; WindingCenter( face->w, offset ); // UNDONE: Export epsilon from original face clipping code ClassifyWindingEpsilon_Offset(face->w, plane->normal, plane->dist, 0.001, &frontwinding, &backwinding, &onwinding, -offset); if ( onwinding ) { // face is in the split plane, go down the appropriate side according to the facing direction assert( frontwinding == NULL ); assert( backwinding == NULL ); if ( DotProduct( g_MainMap->mapplanes[face->planenum].normal, g_MainMap->mapplanes[node->planenum].normal ) > 0 ) { frontwinding = onwinding; } else { backwinding = onwinding; } } if ( frontwinding ) { face_t *tmp = NewFaceFromFace( face ); tmp->w = frontwinding; referenced = MergeFace_r( node->children[0], tmp, original ); } if ( backwinding ) { face_t *tmp = NewFaceFromFace( face ); tmp->w = backwinding; bool test = MergeFace_r( node->children[1], tmp, original ); referenced = referenced || test; } } FreeFace( face ); return referenced; }
void LeakFile(tree_t * tree) #endif { vec3_t mid; FILE *linefile; char filename[1024]; node_t *node; int count; #if defined(USE_XML) xmlNodePtr xml_node, point; #endif if(!tree->outside_node.occupied) { #if defined(USE_XML) return NULL; #endif } Sys_FPrintf(SYS_VRB, "--- LeakFile ---\n"); // // write the points to the file // sprintf(filename, "%s.lin", source); linefile = fopen(filename, "w"); if(!linefile) Error("Couldn't open %s", filename); #if defined(USE_XML) xml_node = xmlNewNode(NULL, "polyline"); #endif count = 0; node = &tree->outside_node; while(node->occupied > 1) { int next; portal_t *p, *nextportal = NULL; // STFU, compiler node_t *nextnode = NULL; // STFU, compiler int s; // find the best portal exit next = node->occupied; for(p = node->portals; p; p = p->next[!s]) { s = (p->nodes[0] == node); if(p->nodes[s]->occupied && p->nodes[s]->occupied < next) { nextportal = p; nextnode = p->nodes[s]; next = nextnode->occupied; } } node = nextnode; WindingCenter(nextportal->winding, mid); fprintf(linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); #if defined(USE_XML) point = xml_NodeForVec(mid); xmlAddChild(xml_node, point); #endif count++; } // add the occupant center GetVectorForKey(node->occupant, "origin", mid); fprintf(linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); #if defined(USE_XML) point = xml_NodeForVec(mid); xmlAddChild(xml_node, point); #endif Sys_FPrintf(SYS_VRB, "%9d point linefile\n", count + 1); fclose(linefile); #if defined(USE_XML) return xml_node; #endif }
/* ============= SubdividePatch ============= */ void SubdividePatch (patch_t *patch) { winding_t *w, *o1, *o2; vec3_t total; vec3_t split; vec_t dist; vec_t widest = -1; int i, j, widest_axis = -1; int subdivide_it = 0; vec_t v; patch_t *newp; w = patch->winding; VectorSubtract (patch->maxs, patch->mins, total); for (i=0 ; i<3 ; i++) { if ( total[i] > widest ) { widest_axis = i; widest = total[i]; } if ( total[i] > patch->chop || (patch->face_maxs[i] == patch->maxs[i] || patch->face_mins[i] == patch->mins[i] ) && total[i] > minchop ) { subdivide_it = 1; } } if ( subdivide_it ) { // // split the winding // VectorCopy (vec3_origin, split); split[widest_axis] = 1; dist = (patch->mins[widest_axis] + patch->maxs[widest_axis])*0.5f; ClipWinding (w, split, dist, &o1, &o2); // // create a new patch // if (num_patches == MAX_PATCHES) Error ("MAX_PATCHES"); newp = &patches[num_patches]; newp->next = patch->next; patch->next = newp; patch->winding = o1; newp->winding = o2; VectorCopy( patch->face_mins, newp->face_mins ); VectorCopy( patch->face_maxs, newp->face_maxs ); VectorCopy( patch->baselight, newp->baselight ); VectorCopy( patch->directlight, newp->directlight ); VectorCopy( patch->totallight, newp->totallight ); VectorCopy( patch->reflectivity, newp->reflectivity ); newp->plane = patch->plane; newp->sky = patch->sky; newp->chop = patch->chop; newp->faceNumber = patch->faceNumber; num_patches++; patch->area = WindingArea (patch->winding); newp->area = WindingArea (newp->winding); WindingCenter (patch->winding, patch->origin); WindingCenter (newp->winding, newp->origin); #ifdef PHONG_NORMAL_PATCHES // This seems to be a bad idea for some reason. Leave it turned off for now. // Set (Copy or Calculate) the synthetic normal for these new patches VectorAdd (patch->origin, patch->plane->normal, patch->origin); VectorAdd (newp->origin, newp->plane->normal, newp->origin); GetPhongNormal( patch->faceNumber, patch->origin, patch->normal ); GetPhongNormal( newp->faceNumber, newp->origin, newp->normal ); VectorSubtract( patch->origin, patch->plane->normal, patch->origin); VectorSubtract( newp->origin, newp->plane->normal, newp->origin); #else VectorCopy( patch->plane->normal, patch->normal ); VectorCopy( newp->plane->normal, newp->normal ); #endif VectorAdd( patch->origin, patch->normal, patch->origin ); VectorAdd( newp->origin, newp->normal, newp->origin ); WindingBounds(patch->winding, patch->mins, patch->maxs); WindingBounds(newp->winding, newp->mins, newp->maxs); // Subdivide patch even more if on the edge of the face; this is a hack! VectorSubtract (patch->maxs, patch->mins, total); if ( total[0] < patch->chop && total[1] < patch->chop && total[2] < patch->chop ) for ( i=0; i<3; i++ ) if ( (patch->face_maxs[i] == patch->maxs[i] || patch->face_mins[i] == patch->mins[i] ) && total[i] > minchop ) { patch->chop = max( minchop, patch->chop / 2 ); break; } SubdividePatch (patch); // Subdivide patch even more if on the edge of the face; this is a hack! VectorSubtract (newp->maxs, newp->mins, total); if ( total[0] < newp->chop && total[1] < newp->chop && total[2] < newp->chop ) for ( i=0; i<3; i++ ) if ( (newp->face_maxs[i] == newp->maxs[i] || newp->face_mins[i] == newp->mins[i] ) && total[i] > minchop ) { newp->chop = max( minchop, newp->chop / 2 ); break; } SubdividePatch (newp); } }
void MakePatchForFace (int fn, winding_t *w) { dface_t *f = dfaces + fn; // No patches at all for the sky! if ( !IsSky(f) ) { float area; patch_t *patch; vec3_t light; vec3_t centroid = {0,0,0}; int i, j; texinfo_t *tx = &texinfo[f->texinfo]; area = WindingArea (w); totalarea += area; patch = &patches[num_patches]; if (num_patches == MAX_PATCHES) Error ("num_patches == MAX_PATCHES"); patch->next = face_patches[fn]; face_patches[fn] = patch; if ( texscale ) { // Compute the texture "scale" in s,t for( i=0; i<2; i++ ) { patch->scale[i] = 0.0; for( j=0; j<3; j++ ) patch->scale[i] += tx->vecs[i][j] * tx->vecs[i][j]; patch->scale[i] = sqrt( patch->scale[i] ); } } else patch->scale[0] = patch->scale[1] = 1.0; patch->area = area; patch->chop = maxchop / (int)((patch->scale[0]+patch->scale[1])/2); patch->sky = FALSE; patch->winding = w; if (f->side) patch->plane = &backplanes[f->planenum]; else patch->plane = &dplanes[f->planenum]; for (j=0 ; j<f->numedges ; j++) { int edge = dsurfedges[ f->firstedge + j ]; int edge2 = dsurfedges[ j==f->numedges-1 ? f->firstedge : f->firstedge + j + 1 ]; if (edge > 0) { VectorAdd( dvertexes[dedges[edge].v[0]].point, centroid, centroid ); VectorAdd( dvertexes[dedges[edge].v[1]].point, centroid, centroid ); } else { VectorAdd( dvertexes[dedges[-edge].v[1]].point, centroid, centroid ); VectorAdd( dvertexes[dedges[-edge].v[0]].point, centroid, centroid ); } } VectorScale( centroid, 1.0 / (f->numedges * 2), centroid ); VectorCopy( centroid, face_centroids[fn] ); // Save them for generating the patch normals later. patch->faceNumber = fn; WindingCenter (w, patch->origin); #ifdef PHONG_NORMAL_PATCHES // This seems to be a bad idea for some reason. Leave it turned off for now. VectorAdd (patch->origin, patch->plane->normal, patch->origin); GetPhongNormal( fn, patch->origin, patch->normal ); VectorSubtract (patch->origin, patch->plane->normal, patch->origin); if ( !VectorCompare( patch->plane->normal, patch->normal ) ) patch->chop = 16; // Chop it fine! #else VectorCopy( patch->plane->normal, patch->normal ); #endif VectorAdd (patch->origin, patch->normal, patch->origin); WindingBounds (w, patch->face_mins, patch->face_maxs); VectorCopy( patch->face_mins, patch->mins ); VectorCopy( patch->face_maxs, patch->maxs ); BaseLightForFace( f, light, patch->reflectivity ); VectorCopy( light, patch->totallight ); VectorCopy( light, patch->baselight ); // Chop all texlights very fine. if ( !VectorCompare( light, vec3_origin ) ) patch->chop = extra ? minchop / 2 : minchop; num_patches++; } }
static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, qboolean original, radWinding_t *rw, clipWork_t *cw ) { int i, style; float dist, area, value; vec3_t mins, maxs, normal, d1, d2, cross, color, gradient; light_t *light, *splash; winding_t *w; /* dummy check */ if( rw == NULL || rw->numVerts < 3 ) return; /* get bounds for winding */ ClearBounds( mins, maxs ); for( i = 0; i < rw->numVerts; i++ ) AddPointToBounds( rw->verts[ i ].xyz, mins, maxs ); /* subdivide if necessary */ for( i = 0; i < 3; i++ ) { if( maxs[ i ] - mins[ i ] > subdivide ) { radWinding_t front, back; /* make axial plane */ VectorClear( normal ); normal[ i ] = 1; dist = (maxs[ i ] + mins[ i ]) * 0.5f; /* clip the winding */ RadClipWindingEpsilon( rw, normal, dist, RADIOSITY_CLIP_EPSILON, &front, &back, cw ); /* recurse */ RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &front, cw ); RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &back, cw ); return; } } /* check area */ area = 0.0f; for( i = 2; i < rw->numVerts; i++ ) { VectorSubtract( rw->verts[ i - 1 ].xyz, rw->verts[ 0 ].xyz, d1 ); VectorSubtract( rw->verts[ i ].xyz, rw->verts[ 0 ].xyz, d2 ); CrossProduct( d1, d2, cross ); area += 0.5f * VectorLength( cross ); } if( area < 1.0f || area > 20000000.0f ) return; /* more subdivision may be necessary */ if( bouncing ) { /* get color sample for the surface fragment */ RadSample( lightmapNum, ds, lm, si, rw, color, gradient, &style ); /* if color gradient is too high, subdivide again */ if( subdivide > minDiffuseSubdivide && (gradient[ 0 ] > RADIOSITY_MAX_GRADIENT || gradient[ 1 ] > RADIOSITY_MAX_GRADIENT || gradient[ 2 ] > RADIOSITY_MAX_GRADIENT) ) { RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, (subdivide / 2.0f), qfalse, rw, cw ); return; } } /* create a regular winding and an average normal */ w = AllocWinding( rw->numVerts ); w->numpoints = rw->numVerts; VectorClear( normal ); for( i = 0; i < rw->numVerts; i++ ) { VectorCopy( rw->verts[ i ].xyz, w->p[ i ] ); VectorAdd( normal, rw->verts[ i ].normal, normal ); } VectorScale( normal, (1.0f / rw->numVerts), normal ); if( VectorNormalize( normal, normal ) == 0.0f ) return; /* early out? */ if( bouncing && VectorLength( color ) < RADIOSITY_MIN ) return; /* debug code */ //% Sys_Printf( "Size: %d %d %d\n", (int) (maxs[ 0 ] - mins[ 0 ]), (int) (maxs[ 1 ] - mins[ 1 ]), (int) (maxs[ 2 ] - mins[ 2 ]) ); //% Sys_Printf( "Grad: %f %f %f\n", gradient[ 0 ], gradient[ 1 ], gradient[ 2 ] ); /* increment counts */ numDiffuseLights++; switch( ds->surfaceType ) { case MST_PLANAR: numBrushDiffuseLights++; break; case MST_TRIANGLE_SOUP: numTriangleDiffuseLights; break; case MST_PATCH: numPatchDiffuseLights++; break; } /* create a light */ light = safe_malloc( sizeof( *light ) ); memset( light, 0, sizeof( *light ) ); /* attach it */ ThreadLock(); light->next = lights; lights = light; ThreadUnlock(); /* initialize the light */ light->flags = LIGHT_AREA_DEFAULT; light->type = EMIT_AREA; light->si = si; light->fade = 1.0f; light->w = w; /* set falloff threshold */ light->falloffTolerance = falloffTolerance; /* bouncing light? */ if( bouncing == qfalse ) { /* handle first-pass lights in normal q3a style */ value = si->value; light->photons = value * area * areaScale; light->add = value * formFactorValueScale * areaScale; VectorCopy( si->color, light->color ); VectorScale( light->color, light->add, light->emitColor ); light->style = noStyles ? LS_NORMAL : si->lightStyle; if( light->style < LS_NORMAL || light->style >= LS_NONE ) light->style = LS_NORMAL; /* set origin */ VectorAdd( mins, maxs, light->origin ); VectorScale( light->origin, 0.5f, light->origin ); /* nudge it off the plane a bit */ VectorCopy( normal, light->normal ); VectorMA( light->origin, 1.0f, light->normal, light->origin ); light->dist = DotProduct( light->origin, normal ); /* optionally create a point splashsplash light for first pass */ if( original && si->backsplashFraction > 0 ) { /* allocate a new point light */ splash = safe_malloc( sizeof( *splash ) ); memset( splash, 0, sizeof( *splash ) ); splash->next = lights; lights = splash; /* set it up */ splash->flags = LIGHT_Q3A_DEFAULT; splash->type = EMIT_POINT; splash->photons = light->photons * si->backsplashFraction; splash->fade = 1.0f; splash->si = si; VectorMA( light->origin, si->backsplashDistance, normal, splash->origin ); VectorCopy( si->color, splash->color ); splash->falloffTolerance = falloffTolerance; splash->style = noStyles ? LS_NORMAL : light->style; /* add to counts */ numPointLights++; } } else { /* handle bounced light (radiosity) a little differently */ value = RADIOSITY_VALUE * si->bounceScale * 0.375f; light->photons = value * area * bounceScale; light->add = value * formFactorValueScale * bounceScale; VectorCopy( color, light->color ); VectorScale( light->color, light->add, light->emitColor ); light->style = noStyles ? LS_NORMAL : style; if( light->style < LS_NORMAL || light->style >= LS_NONE ) light->style = LS_NORMAL; /* set origin */ WindingCenter( w, light->origin ); /* nudge it off the plane a bit */ VectorCopy( normal, light->normal ); VectorMA( light->origin, 1.0f, light->normal, light->origin ); light->dist = DotProduct( light->origin, normal ); } /* emit light from both sides? */ if( si->compileFlags & C_FOG || si->twoSided ) light->flags |= LIGHT_TWOSIDED; //% Sys_Printf( "\nAL: C: (%6f, %6f, %6f) [%6f] N: (%6f, %6f, %6f) %s\n", //% light->color[ 0 ], light->color[ 1 ], light->color[ 2 ], light->add, //% light->normal[ 0 ], light->normal[ 1 ], light->normal[ 2 ], //% light->si->shader ); }
void MakePatchForFace( int fn, winding_t *w ){ dface_t *f; float area; patch_t *patch; dplane_t *pl; int i; vec3_t color; dleaf_t *leaf; f = &dfaces[fn]; area = WindingArea( w ); totalarea += area; patch = &patches[num_patches]; if ( num_patches == MAX_PATCHES ) { Error( "num_patches == MAX_PATCHES" ); } patch->next = face_patches[fn]; face_patches[fn] = patch; patch->winding = w; if ( f->side ) { patch->plane = &backplanes[f->planenum]; } else{ patch->plane = &dplanes[f->planenum]; } if ( face_offset[fn][0] || face_offset[fn][1] || face_offset[fn][2] ) { // origin offset faces must create new planes if ( numplanes + fakeplanes >= MAX_MAP_PLANES ) { Error( "numplanes + fakeplanes >= MAX_MAP_PLANES" ); } pl = &dplanes[numplanes + fakeplanes]; fakeplanes++; *pl = *( patch->plane ); pl->dist += DotProduct( face_offset[fn], pl->normal ); patch->plane = pl; } WindingCenter( w, patch->origin ); VectorAdd( patch->origin, patch->plane->normal, patch->origin ); leaf = Rad_PointInLeaf( patch->origin ); patch->cluster = leaf->cluster; if ( patch->cluster == -1 ) { Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n" ); } patch->area = area; if ( patch->area <= 1 ) { patch->area = 1; } patch->sky = IsSky( f ); VectorCopy( texture_reflectivity[f->texinfo], patch->reflectivity ); // non-bmodel patches can emit light if ( fn < dmodels[0].numfaces ) { BaseLightForFace( f, patch->baselight ); ColorNormalize( patch->reflectivity, color ); for ( i = 0 ; i < 3 ; i++ ) patch->baselight[i] *= color[i]; VectorCopy( patch->baselight, patch->totallight ); } num_patches++; }
radial_t *BuildPatchRadial( int facenum ) { int j; radial_t *rad; CPatch *patch; faceneighbor_t *fn; Vector2D mins, maxs; bool needsBumpmap, neighborNeedsBumpmap; needsBumpmap = texinfo[g_pFaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false; rad = AllocateRadial( facenum ); fn = &faceneighbor[ rad->facenum ]; CPatch *pNextPatch; if( g_FacePatches.Element( rad->facenum ) != g_FacePatches.InvalidIndex() ) { for( patch = &g_Patches.Element( g_FacePatches.Element( rad->facenum ) ); patch; patch = pNextPatch ) { // next patch pNextPatch = NULL; if( patch->ndxNext != g_Patches.InvalidIndex() ) { pNextPatch = &g_Patches.Element( patch->ndxNext ); } // skip patches with children if (patch->child1 != g_Patches.InvalidIndex() ) continue; // get the range of patch lightmap texture coords int ndxPatch = patch - g_Patches.Base(); PatchLightmapCoordRange( rad, ndxPatch, mins, maxs ); if (patch->numtransfers == 0) { // Error, using patch that was never evaluated or has no samples // patch->totallight[1] = 255; } // // displacement surface patch origin position and normal vectors have been changed to // represent the displacement surface position and normal -- for radial "blending" // we need to get the base surface patch origin! // if( ValidDispFace( &g_pFaces[facenum] ) ) { Vector patchOrigin; WindingCenter (patch->winding, patchOrigin ); AddBouncedToRadial( rad, patchOrigin, mins, maxs, patch->totallight.light, needsBumpmap, needsBumpmap ); } else { AddBouncedToRadial( rad, patch->origin, mins, maxs, patch->totallight.light, needsBumpmap, needsBumpmap ); } } } for (j=0 ; j<fn->numneighbors; j++) { if( g_FacePatches.Element( fn->neighbor[j] ) != g_FacePatches.InvalidIndex() ) { for( patch = &g_Patches.Element( g_FacePatches.Element( fn->neighbor[j] ) ); patch; patch = pNextPatch ) { // next patch pNextPatch = NULL; if( patch->ndxNext != g_Patches.InvalidIndex() ) { pNextPatch = &g_Patches.Element( patch->ndxNext ); } // skip patches with children if (patch->child1 != g_Patches.InvalidIndex() ) continue; // get the range of patch lightmap texture coords int ndxPatch = patch - g_Patches.Base(); PatchLightmapCoordRange( rad, ndxPatch, mins, maxs ); neighborNeedsBumpmap = texinfo[g_pFaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false; // // displacement surface patch origin position and normal vectors have been changed to // represent the displacement surface position and normal -- for radial "blending" // we need to get the base surface patch origin! // if( ValidDispFace( &g_pFaces[fn->neighbor[j]] ) ) { Vector patchOrigin; WindingCenter (patch->winding, patchOrigin ); AddBouncedToRadial( rad, patchOrigin, mins, maxs, patch->totallight.light, needsBumpmap, needsBumpmap ); } else { AddBouncedToRadial( rad, patch->origin, mins, maxs, patch->totallight.light, needsBumpmap, needsBumpmap ); } } } } return rad; }