⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 light.c

📁 quake3工具源码。包括生成bsp文件
💻 C
📖 第 1 页 / 共 4 页
字号:
			VectorScale( sample, 255/max, sample );
		}

		// save the sample
		for ( j = 0 ; j < 3 ; j++ ) {
			if ( sample[j] > 255 ) {
				sample[j] = 255;
			}
			dv->color[j] = sample[j];
		}

		// Don't bother writing alpha since it will already be set to 255,
		// plus we don't want to write over alpha generated by SetTerrainTextures
		//dv->color[3] = 255;
	}
}


/*
=================
LinearSubdivideMesh

For extra lighting, just midpoint one of the axis.
The edges are clamped at the original edges.
=================
*/
mesh_t *LinearSubdivideMesh( mesh_t *in ) {
	int			i, j;
	mesh_t		*out;
	drawVert_t	*v1, *v2, *vout;

	out = malloc( sizeof( *out ) );

	out->width = in->width * 2;
	out->height = in->height;
	out->verts = malloc( out->width * out->height * sizeof(*out->verts) );
	for ( j = 0 ; j < in->height ; j++ ) {
		out->verts[ j * out->width + 0 ] = in->verts[ j * in->width + 0 ];
		out->verts[ j * out->width + out->width - 1 ] = in->verts[ j * in->width + in->width - 1 ];
		for ( i = 1 ; i < out->width - 1 ; i+= 2 ) {
			v1 = in->verts + j * in->width + (i >> 1);
			v2 = v1 + 1;
			vout = out->verts + j * out->width + i;

			vout->xyz[0] = 0.75 * v1->xyz[0] + 0.25 * v2->xyz[0];
			vout->xyz[1] = 0.75 * v1->xyz[1] + 0.25 * v2->xyz[1];
			vout->xyz[2] = 0.75 * v1->xyz[2] + 0.25 * v2->xyz[2];

			vout->normal[0] = 0.75 * v1->normal[0] + 0.25 * v2->normal[0];
			vout->normal[1] = 0.75 * v1->normal[1] + 0.25 * v2->normal[1];
			vout->normal[2] = 0.75 * v1->normal[2] + 0.25 * v2->normal[2];

			VectorNormalize( vout->normal, vout->normal );

			vout++;

			vout->xyz[0] = 0.25 * v1->xyz[0] + 0.75 * v2->xyz[0];
			vout->xyz[1] = 0.25 * v1->xyz[1] + 0.75 * v2->xyz[1];
			vout->xyz[2] = 0.25 * v1->xyz[2] + 0.75 * v2->xyz[2];

			vout->normal[0] = 0.25 * v1->normal[0] + 0.75 * v2->normal[0];
			vout->normal[1] = 0.25 * v1->normal[1] + 0.75 * v2->normal[1];
			vout->normal[2] = 0.25 * v1->normal[2] + 0.75 * v2->normal[2];

			VectorNormalize( vout->normal, vout->normal );

		}
	}

	FreeMesh( in );

	return out;
}

/*
==============
ColorToBytes
==============
*/
void ColorToBytes( const float *color, byte *colorBytes ) {
	float	max;
	vec3_t	sample;

	VectorCopy( color, sample );

	// clamp with color normalization
	max = sample[0];
	if ( sample[1] > max ) {
		max = sample[1];
	}
	if ( sample[2] > max ) {
		max = sample[2];
	}
	if ( max > 255 ) {
		VectorScale( sample, 255/max, sample );
	}
	colorBytes[ 0 ] = sample[0];
	colorBytes[ 1 ] = sample[1];
	colorBytes[ 2 ] = sample[2];
}



/*
=============
TraceLtm
=============
*/
void TraceLtm( int num ) {
	dsurface_t	*ds;
	int			i, j, k;
	int			x, y;
	int			position, numPositions;
	vec3_t		base, origin, normal;
	byte		occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE];
	vec3_t		color[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE];
	traceWork_t	tw;
	vec3_t		average;
	int			count;
	mesh_t		srcMesh, *mesh, *subdivided;
	shaderInfo_t	*si;
	static float	nudge[2][9] = {
		{ 0, -1, 0, 1, -1, 1, -1, 0, 1 },
		{ 0, -1, -1, -1, 0, 0, 1, 1, 1 }
	};
	int			sampleWidth, sampleHeight, ssize;
	vec3_t		lightmapOrigin, lightmapVecs[2];
	int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_WIDTH];

	ds = &drawSurfaces[num];
	si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );

	// vertex-lit triangle model
	if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
		VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw );
		return;
	}
	
	if ( ds->lightmapNum == -1 ) {
		return;		// doesn't need lighting at all
	}

	if (!novertexlighting) {
		// calculate the vertex lighting for gouraud shade mode
		VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw );
	}

	if ( ds->lightmapNum < 0 ) {
		return;		// doesn't need lightmap lighting
	}

	si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
	ssize = samplesize;
	if (si->lightmapSampleSize)
		ssize = si->lightmapSampleSize;

	if (si->patchShadows)
		tw.patchshadows = qtrue;
	else
		tw.patchshadows = patchshadows;

	if ( ds->surfaceType == MST_PATCH ) {
		srcMesh.width = ds->patchWidth;
		srcMesh.height = ds->patchHeight;
		srcMesh.verts = drawVerts + ds->firstVert;
		mesh = SubdivideMesh( srcMesh, 8, 999 );
		PutMeshOnCurve( *mesh );
		MakeMeshNormals( *mesh );

		subdivided = RemoveLinearMeshColumnsRows( mesh );
		FreeMesh(mesh);

		mesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_WIDTH, widthtable, heighttable);
		if ( mesh->width != ds->lightmapWidth || mesh->height != ds->lightmapHeight ) {
			Error( "Mesh lightmap miscount");
		}

		if ( extra ) {
			mesh_t	*mp;

			// chop it up for more light samples (leaking memory...)
			mp = mesh;//CopyMesh( mesh );
			mp = LinearSubdivideMesh( mp );
			mp = TransposeMesh( mp );
			mp = LinearSubdivideMesh( mp );
			mp = TransposeMesh( mp );

			mesh = mp;
		}
	} else {
		VectorCopy( ds->lightmapVecs[2], normal );

		if ( !extra ) {
			VectorCopy( ds->lightmapOrigin, lightmapOrigin );
			VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] );
			VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] );
		} else {
			// sample at a closer spacing for antialiasing
			VectorCopy( ds->lightmapOrigin, lightmapOrigin );
			VectorScale( ds->lightmapVecs[0], 0.5, lightmapVecs[0] );
			VectorScale( ds->lightmapVecs[1], 0.5, lightmapVecs[1] );
			VectorMA( lightmapOrigin, -0.5, lightmapVecs[0], lightmapOrigin );
			VectorMA( lightmapOrigin, -0.5, lightmapVecs[1], lightmapOrigin );
		}
	}

	if ( extra ) {
		sampleWidth = ds->lightmapWidth * 2;
		sampleHeight = ds->lightmapHeight * 2;
	} else {
		sampleWidth = ds->lightmapWidth;
		sampleHeight = ds->lightmapHeight;
	}

	memset ( color, 0, sizeof( color ) );

	// determine which samples are occluded
	memset ( occluded, 0, sizeof( occluded ) );
	for ( i = 0 ; i < sampleWidth ; i++ ) {
		for ( j = 0 ; j < sampleHeight ; j++ ) {

			if ( ds->patchWidth ) {
				numPositions = 9;
				VectorCopy( mesh->verts[j*mesh->width+i].normal, normal );
				// VectorNormalize( normal, normal );
				// push off of the curve a bit
				VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base );

				MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] );
			} else {
				numPositions = 9;
				for ( k = 0 ; k < 3 ; k++ ) {
					base[k] = lightmapOrigin[k] + normal[k]
						+ i * lightmapVecs[0][k] 
						+ j * lightmapVecs[1][k];
				}
			}
			VectorAdd( base, surfaceOrigin[ num ], base );

			// we may need to slightly nudge the sample point
			// if directly on a wall
			for ( position = 0 ; position < numPositions ; position++ ) {
				// calculate lightmap sample position
				for ( k = 0 ; k < 3 ; k++ ) {
					origin[k] = base[k] + 
						+ ( nudge[0][position]/16 ) * lightmapVecs[0][k] 
						+ ( nudge[1][position]/16 ) * lightmapVecs[1][k];
				}

				if ( notrace ) {
					break;
				}
				if ( !PointInSolid( origin ) ) {
					break;
				}
			}

			// if none of the nudges worked, this sample is occluded
			if ( position == numPositions ) {
				occluded[i][j] = qtrue;
				if ( numthreads == 1 ) {
					c_occluded++;
				}
				continue;
			}
			
			if ( numthreads == 1 ) {
				c_visible++;
			}
			occluded[i][j] = qfalse;
			LightingAtSample( origin, normal, color[i][j], qtrue, qfalse, &tw );
		}
	}

	if ( dump ) {
		PrintOccluded( occluded, sampleWidth, sampleHeight );
	}

	// calculate average values for occluded samples
	for ( i = 0 ; i < sampleWidth ; i++ ) {
		for ( j = 0 ; j < sampleHeight ; j++ ) {
			if ( !occluded[i][j] ) {
				continue;
			}
			// scan all surrounding samples
			count = 0;
			VectorClear( average );
			for ( x = -1 ; x <= 1; x++ ) {
				for ( y = -1 ; y <= 1 ; y++ ) {
					if ( i + x < 0 || i + x >= sampleWidth ) {
						continue;
					}
					if ( j + y < 0 || j + y >= sampleHeight ) {
						continue;
					}
					if ( occluded[i+x][j+y] ) {
						continue;
					}
					count++;
					VectorAdd( color[i+x][j+y], average, average );
				}
			}
			if ( count ) {
				VectorScale( average, 1.0/count, color[i][j] );
			}
		}
	}

	// average together the values if we are extra sampling
	if ( ds->lightmapWidth != sampleWidth ) {
		for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
			for ( j = 0 ; j < ds->lightmapHeight ; j++ ) {
				for ( k = 0 ; k < 3 ; k++ ) {
					float		value, coverage;

					value = color[i*2][j*2][k] + color[i*2][j*2+1][k] +
						color[i*2+1][j*2][k] + color[i*2+1][j*2+1][k];
					coverage = 4;
					if ( extraWide ) {
						// wider than box filter
						if ( i > 0 ) {
							value += color[i*2-1][j*2][k] + color[i*2-1][j*2+1][k];
							value += color[i*2-2][j*2][k] + color[i*2-2][j*2+1][k];
							coverage += 4;
						}
						if ( i < ds->lightmapWidth - 1 ) {
							value += color[i*2+2][j*2][k] + color[i*2+2][j*2+1][k];
							value += color[i*2+3][j*2][k] + color[i*2+3][j*2+1][k];
							coverage += 4;
						}
						if ( j > 0 ) {
							value += color[i*2][j*2-1][k] + color[i*2+1][j*2-1][k];
							value += color[i*2][j*2-2][k] + color[i*2+1][j*2-2][k];
							coverage += 4;
						}
						if ( j < ds->lightmapHeight - 1 ) {
							value += color[i*2][j*2+2][k] + color[i*2+1][j*2+2][k];
							value += color[i*2][j*2+3][k] + color[i*2+1][j*2+3][k];
							coverage += 2;
						}
					}

					color[i][j][k] = value / coverage;
				}
			}
		}
	}

	// optionally create a debugging border around the lightmap
	if ( lightmapBorder ) {
		for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
			color[i][0][0] = 255;
			color[i][0][1] = 0;
			color[i][0][2] = 0;

			color[i][ds->lightmapHeight-1][0] = 255;
			color[i][ds->lightmapHeight-1][1] = 0;
			color[i][ds->lightmapHeight-1][2] = 0;
		}
		for ( i = 0 ; i < ds->lightmapHeight ; i++ ) {
			color[0][i][0] = 255;
			color[0][i][1] = 0;
			color[0][i][2] = 0;

			color[ds->lightmapWidth-1][i][0] = 255;
			color[ds->lightmapWidth-1][i][1] = 0;
			color[ds->lightmapWidth-1][i][2] = 0;
		}
	}

	// clamp the colors to bytes and store off
	for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
		for ( j = 0 ; j < ds->lightmapHeight ; j++ ) {
			k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j) 
				* LIGHTMAP_WIDTH + ds->lightmapX + i;

			ColorToBytes( color[i][j], lightBytes + k*3 );
		}
	}

	if (ds->surfaceType == MST_PATCH)
	{
		FreeMesh(mesh);
	}
}


//=============================================================================

vec3_t	gridMins;
vec3_t	gridSize = { 64, 64, 128 };
int		gridBounds[3];


/*
========================
LightContributionToPoint
========================
*/
qboolean LightContributionToPoint( const light_t *light, const vec3_t origin,
								  vec3_t color, traceWork_t *tw ) {
	trace_t		trace;
	float		add;

	add = 0;

	VectorClear( color );

	// testing exact PTPFF
	if ( exactPointToPolygon && light->type == emit_area ) {
		float		factor;
		float		d;
		vec3_t		normal;

		// see if the point is behind the light
		d = DotProduct( origin, light->normal ) - light->dist;
		if ( !light->twosided ) {
			if ( d < 1 ) {
				return qfalse;		// point is behind light
			}
		}

		// test occlusion
		// clip the line, tracing from the surface towards the light
		TraceLine( origin, light->origin, &trace, qfalse, tw );
		if ( trace.passSolid ) {
			return qfalse;
		}

		// calculate the contribution
		VectorSubtract( light->origin, origin, normal );
		if ( VectorNormalize( normal, normal ) == 0 ) {
			return qfalse;
		}
		factor = PointToPolygonFormFactor( origin, normal, light->w );
		if ( factor <= 0 ) {
			if ( light->twosided ) {
				factor = -factor;
			} else {
				return qfalse;
			}
		}
		VectorScale( light->emitColor, factor, color );
		return qtrue;
	}

	// calculate the amount of light at this sample
	if ( light->type == emit_point || light->type == emit_spotlight ) {
		vec3_t		dir;
		float		dist;

		VectorSubtract( light->origin, origin, dir );
		dist = VectorLength( dir );
		// clamp the distance to prevent super hot spots
		if ( dist < 16 ) {
			dist = 16;
		}
		if ( light->linearLight ) {
			add = light->photons * linearScale - dist;
			if ( add < 0 ) {
				add = 0;
			}
		} else {
			add = light->photons / ( dist * dist );
		}
	} else {
		return qfalse;
	}

	if ( add <= 1.0 ) {
		return qfalse;
	}

	// clip the line, tracing from the surface towards the light
	TraceLine( origin, light->origin, &trace, qfalse, tw );

	// other light rays must not hit anything
	if ( trace.passSolid ) {
		return qfalse;
	}

	// add the result
	color[0] = add * light->color[0];
	color[1] = add * light->color[1];
	color[2] = add * light->color[2];

	return qtrue;
}

typedef struct {
	vec3_t		dir;
	vec3_t		color;
} contribution_t;

/*
=============
TraceGrid

Grid samples are foe quickly determining the lighting
of dynamically placed entities in the world
=============
*/
#define	MAX_CONTRIBUTIONS	1024
void TraceGrid( int num ) {
	int			x, y, z;
	vec3_t		origin;
	light_t		*light;
	vec3_t		color;
	int			mod;
	vec3_t		directedColor;
	vec3_t		summedDir;
	contribution_t	contributions[MAX_CONTRIBUTIONS];
	int			numCon;
	int			i;
	traceWork_t	tw;
	float		addSize;

	mod = num;
	z = mod / ( gridBounds[0] * gridBounds[1] );
	mod -= z * ( gridBounds[0] * gridBounds[1] );

	y = mod / gridBounds[0];
	mod -= y * gridBounds[0];

	x = mod;

	origin[0] = gridMins[0] + x * gridSize[0];
	origin[1] = gridMins[1] + y * gridSize[1];
	origin[2] = gridMins[2] + z * gridSize[2];

	if ( PointInSolid( origin ) ) {
		vec3_t	baseOrigin;
		int		step;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -