Example #1
0
/*
=============
RB_SwapBuffers

=============
*/
const void	RB_SwapBuffers( const void *data ) {
	// texture swapping test
	if ( r_showImages.GetInteger() != 0 ) {
		RB_ShowImages();
	}

	// force a gl sync if requested
	if ( r_finish.GetBool() ) {
		qglFinish();
	}

    RB_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" );

	// don't flip if drawing to front buffer
	if ( !r_frontBuffer.GetBool() ) {
	    GLimp_SwapBuffers();
	}
}
Example #2
0
/*
==============
RenderBumpTriangles

==============
*/
static void RenderBumpTriangles( srfTriangles_t *lowMesh, renderBump_t *rb ) {
	int		i, j;

	RB_SetGL2D();

	qglDisable( GL_CULL_FACE );

	qglColor3f( 1, 1, 1 );

	qglMatrixMode( GL_PROJECTION );
	qglLoadIdentity();
	qglOrtho( 0, 1, 1, 0, -1, 1 );
	qglDisable( GL_BLEND );
	qglMatrixMode( GL_MODELVIEW );
	qglLoadIdentity();

	qglDisable( GL_DEPTH_TEST );

	qglClearColor(1,0,0,1);
	qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	qglColor3f( 1, 1, 1 );

	// create smoothed normals for the surface, which might be
	// different than the normals at the vertexes if the
	// surface uses unsmoothedNormals, which only takes the
	// normal from a single triangle.  We need properly smoothed
	// normals to make sure that the traces always go off normal
	// to the true surface.
	idVec3	*lowMeshNormals = (idVec3 *)Mem_ClearedAlloc( lowMesh->numVerts * sizeof( *lowMeshNormals ) );
	R_DeriveFacePlanes( lowMesh );
	R_CreateSilIndexes( lowMesh );	// recreate, merging the mirrored verts back together
	const idPlane *planes = lowMesh->facePlanes;
	for ( i = 0 ; i < lowMesh->numIndexes ; i += 3, planes++ ) {
		for ( j = 0 ; j < 3 ; j++ ) {
			int		index;

			index = lowMesh->silIndexes[i+j];
			lowMeshNormals[index] += (*planes).Normal();
		}
	}
	// normalize and replicate from silIndexes to all indexes
	for ( i = 0 ; i < lowMesh->numIndexes ; i++ ) {
		lowMeshNormals[lowMesh->indexes[i]] = lowMeshNormals[lowMesh->silIndexes[i]];
		lowMeshNormals[lowMesh->indexes[i]].Normalize();
	}


	// rasterize each low poly face
	for ( j = 0 ; j < lowMesh->numIndexes ; j+=3 ) {
		// pump the event loop so the window can be dragged around
		Sys_GenerateEvents();

		RasterizeTriangle( lowMesh, lowMeshNormals, j/3, rb );

		qglClearColor(1,0,0,1);
		qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
		qglRasterPos2f( 0, 1 );
		qglPixelZoom( glConfig.vidWidth / (float)rb->width, glConfig.vidHeight / (float)rb->height );
		qglDrawPixels( rb->width, rb->height, GL_RGBA, GL_UNSIGNED_BYTE, rb->localPic );
		qglPixelZoom( 1, 1 );
		qglFlush();
		GLimp_SwapBuffers();
	}

	Mem_Free( lowMeshNormals );
}
Example #3
0
/*
==============
RenderBumpFlat_f

==============
*/
void RenderBumpFlat_f( const idCmdArgs &args ) {
	int		width, height;
	idStr	source;
	int		i;
	idBounds	bounds;
	srfTriangles_t	*mesh;

	// update the screen as we print
	common->SetRefreshOnPrint( true );

	width = height = 256;

	// check options
	for ( i = 1 ; i < args.Argc() - 1; i++ ) {
		const char *s;

		s = args.Argv( i );
		if ( s[0] == '-' ) {
			i++;
			s = args.Argv( i );
		}

		if ( !idStr::Icmp( s, "size" ) ) {
			if ( i + 2 >= args.Argc() ) {
				i = args.Argc();
				break;
			}
			width = atoi( args.Argv( i + 1 ) );
			height = atoi( args.Argv( i + 2 ) );
			i += 2;
		} else {
			common->Printf( "WARNING: Unknown option \"%s\"\n", s );
			break;
		}
	}

	if ( i != ( args.Argc() - 1 ) ) {
		common->Error( "usage: renderBumpFlat [-size width height] asefile" );
		return;
	}

	common->Printf( "Final image size: %i, %i\n", width, height );

	// load the source in "fastload" mode, because we don't
	// need tangent and shadow information
	source = args.Argv( i );

	idRenderModel *highPolyModel = renderModelManager->AllocModel();

	highPolyModel->PartialInitFromFile( source );

	if ( highPolyModel->IsDefaultModel() ) {
		common->Error( "failed to load %s", source.c_str() );
	}

	// combine the high poly model into a single polyset
	if ( highPolyModel->NumSurfaces() != 1 ) {
		highPolyModel = CombineModelSurfaces( highPolyModel );
	}

	// create normals if not present in file
	const modelSurface_t *surf = highPolyModel->Surface( 0 );
	mesh = surf->geometry;

	// bound the entire file
	R_BoundTriSurf( mesh );
	bounds = mesh->bounds;

	SaveWindow();
	ResizeWindow( width, height );

	// for small images, the viewport may be less than the minimum window
	qglViewport( 0, 0, width, height );

	qglEnable( GL_CULL_FACE );
	qglCullFace( GL_FRONT );
	qglDisable( GL_STENCIL_TEST );
	qglDisable( GL_SCISSOR_TEST );
	qglDisable( GL_ALPHA_TEST );
	qglDisable( GL_BLEND );
	qglEnable( GL_DEPTH_TEST );
	qglDisable( GL_TEXTURE_2D );
	qglDepthMask( GL_TRUE );
	qglDepthFunc( GL_LEQUAL );

	qglColor3f( 1, 1, 1 );

	qglMatrixMode( GL_PROJECTION );
	qglLoadIdentity();
	qglOrtho( bounds[0][0], bounds[1][0], bounds[0][2],
		bounds[1][2], -( bounds[0][1] - 1 ), -( bounds[1][1] + 1 ) );

	qglMatrixMode( GL_MODELVIEW );
	qglLoadIdentity();

	// flat maps are automatically anti-aliased

	idStr	filename;
	int		j, k, c;
	byte	*buffer;
	int		*sumBuffer, *colorSumBuffer;
	bool	flat;
	int		sample;

	sumBuffer = (int *)Mem_Alloc( width * height * 4 * 4 );
	memset( sumBuffer, 0, width * height * 4 * 4 );
	buffer = (byte *)Mem_Alloc( width * height * 4 );

	colorSumBuffer = (int *)Mem_Alloc( width * height * 4 * 4 );
	memset( sumBuffer, 0, width * height * 4 * 4 );

	flat = false;
//flat = true;

	for ( sample = 0 ; sample < 16 ; sample++ ) {
		float	xOff, yOff;

		xOff = ( ( sample & 3 ) / 4.0 ) * ( bounds[1][0] - bounds[0][0] ) / width;
		yOff = ( ( sample / 4 ) / 4.0 ) * ( bounds[1][2] - bounds[0][2] ) / height;

		for ( int colorPass = 0 ; colorPass < 2 ; colorPass++ ) {
			qglClearColor(0.5,0.5,0.5,0);
			qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

			qglBegin( GL_TRIANGLES );
			for ( i = 0 ; i < highPolyModel->NumSurfaces() ; i++ ) {
				const modelSurface_t *surf = highPolyModel->Surface( i );

				mesh = surf->geometry;

				if ( colorPass ) {
					// just render the surface color for artist visualization
					for ( j = 0 ; j < mesh->numIndexes ; j+=3 ) {
						for ( k = 0 ; k < 3 ; k++ ) {
							int		v;
							float	*a;

							v = mesh->indexes[j+k];
							qglColor3ubv( mesh->verts[v].color );
							a = mesh->verts[v].xyz.ToFloatPtr();
							qglVertex3f( a[0] + xOff, a[2] + yOff, a[1] );
						}
					}
				} else {
					// render as normal map
					// we can either flat shade from the plane,
					// or smooth shade from the vertex normals
					for ( j = 0 ; j < mesh->numIndexes ; j+=3 ) {
						if ( flat ) {
							idPlane		plane;
							idVec3		*a, *b, *c;
							int			v1, v2, v3;

							v1 = mesh->indexes[j+0];
							v2 = mesh->indexes[j+1];
							v3 = mesh->indexes[j+2];

							a = &mesh->verts[ v1 ].xyz;
							b = &mesh->verts[ v2 ].xyz;
							c = &mesh->verts[ v3 ].xyz;

							plane.FromPoints( *a, *b, *c );

							// NULLNORMAL is used by the artists to force an area to reflect no
							// light at all
							if ( surf->shader->GetSurfaceFlags() & SURF_NULLNORMAL ) {
								qglColor3f( 0.5, 0.5, 0.5 );
							} else {
								qglColor3f( 0.5 + 0.5*plane[0], 0.5 - 0.5*plane[2], 0.5 - 0.5*plane[1] );
							}

							qglVertex3f( (*a)[0] + xOff, (*a)[2] + yOff, (*a)[1] );
							qglVertex3f( (*b)[0] + xOff, (*b)[2] + yOff, (*b)[1] );
							qglVertex3f( (*c)[0] + xOff, (*c)[2] + yOff, (*c)[1] );
						} else {
							for ( k = 0 ; k < 3 ; k++ ) {
								int		v;
								float	*n;
								float	*a;

								v = mesh->indexes[j+k];
								n = mesh->verts[v].normal.ToFloatPtr();

								// NULLNORMAL is used by the artists to force an area to reflect no
								// light at all
								if ( surf->shader->GetSurfaceFlags() & SURF_NULLNORMAL ) {
									qglColor3f( 0.5, 0.5, 0.5 );
								} else {
								// we are going to flip the normal Z direction
									qglColor3f( 0.5 + 0.5*n[0], 0.5 - 0.5*n[2], 0.5 - 0.5*n[1] );
								}

								a = mesh->verts[v].xyz.ToFloatPtr();
								qglVertex3f( a[0] + xOff, a[2] + yOff, a[1] );
							}
						}
					}
				}
			}

			qglEnd();
			qglFlush();
			GLimp_SwapBuffers();
			qglReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );

			c = width * height;

			if ( colorPass ) {
				// add to the sum buffer
				for ( i = 0 ; i < c ; i++ ) {
					colorSumBuffer[i*4+0] += buffer[i*4+0];
					colorSumBuffer[i*4+1] += buffer[i*4+1];
					colorSumBuffer[i*4+2] += buffer[i*4+2];
					colorSumBuffer[i*4+3] += buffer[i*4+3];
				}
			} else {
				// normalize
				for ( i = 0 ; i < c ; i++ ) {
					idVec3	v;

					v[0] = ( buffer[i*4+0] - 128 ) / 127.0;
					v[1] = ( buffer[i*4+1] - 128 ) / 127.0;
					v[2] = ( buffer[i*4+2] - 128 ) / 127.0;

					v.Normalize();

					buffer[i*4+0] = 128 + 127 * v[0];
					buffer[i*4+1] = 128 + 127 * v[1];
					buffer[i*4+2] = 128 + 127 * v[2];
				}

				// outline into non-drawn areas
				for ( i = 0 ; i < 8 ; i++ ) {
					OutlineNormalMap( buffer, width, height, 128, 128, 128 );
				}

				// add to the sum buffer
				for ( i = 0 ; i < c ; i++ ) {
					sumBuffer[i*4+0] += buffer[i*4+0];
					sumBuffer[i*4+1] += buffer[i*4+1];
					sumBuffer[i*4+2] += buffer[i*4+2];
					sumBuffer[i*4+3] += buffer[i*4+3];
				}
			}
		}
	}

	c = width * height;

	// save out the color map
	for ( i = 0 ; i < c ; i++ ) {
		buffer[i*4+0] = colorSumBuffer[i*4+0] / 16;
		buffer[i*4+1] = colorSumBuffer[i*4+1] / 16;
		buffer[i*4+2] = colorSumBuffer[i*4+2] / 16;
		buffer[i*4+3] = colorSumBuffer[i*4+3] / 16;
	}
	filename = source;
	filename.StripFileExtension();
	filename.Append( "_color.tga" );
	R_VerticalFlip( buffer, width, height );
	R_WriteTGA( filename, buffer, width, height );

	// save out the local map
	// scale the sum buffer back down to the sample buffer
	// we allow this to denormalize
	for ( i = 0 ; i < c ; i++ ) {
		buffer[i*4+0] = sumBuffer[i*4+0] / 16;
		buffer[i*4+1] = sumBuffer[i*4+1] / 16;
		buffer[i*4+2] = sumBuffer[i*4+2] / 16;
		buffer[i*4+3] = sumBuffer[i*4+3] / 16;
	}

	filename = source;
	filename.StripFileExtension();
	filename.Append( "_local.tga" );
	common->Printf( "writing %s (%i,%i)\n", filename.c_str(), width, height );
	R_VerticalFlip( buffer, width, height );
	R_WriteTGA( filename, buffer, width, height );


	// free the model
	renderModelManager->FreeModel( highPolyModel );

	// free our work buffer
	Mem_Free( buffer );
	Mem_Free( sumBuffer );
	Mem_Free( colorSumBuffer );

	RestoreWindow();

	// stop updating the screen as we print
	common->SetRefreshOnPrint( false );

	common->Error( "Completed." );
}