Example #1
0
/*
==================
RB_ReadPixels

Reads an image but takes care of alignment issues for reading RGB images.
Prepends the specified number of (uninitialized) bytes to the buffer.

The returned buffer must be freed with ri.Hunk_FreeTempMemory().
==================
*/
static byte *RB_ReadPixels( int x, int y, int width, int height, size_t offset )
{
	GLint packAlign;
	int   lineLen, paddedLineLen;
	byte  *buffer, *pixels;
	int   i;

	glGetIntegerv( GL_PACK_ALIGNMENT, &packAlign );

	lineLen = width * 3;
	paddedLineLen = PAD( lineLen, packAlign );

	// Allocate a few more bytes so that we can choose an alignment we like
	buffer = ( byte * ) ri.Hunk_AllocateTempMemory( offset + paddedLineLen * height + packAlign - 1 );

	pixels = ( byte * ) PADP( buffer + offset, packAlign );
	glReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels );

	// Drop alignment and line padding bytes
	for ( i = 0; i < height; ++i )
	{
		memmove( buffer + offset + i * lineLen, pixels + i * paddedLineLen, lineLen );
	}

	return buffer;
}
Example #2
0
/*
 * RB_ExecuteRenderCommands
 *
 * This function will be called synchronously if running without
 * smp extensions, or asynchronously by another thread.
 */
void
RB_ExecuteRenderCommands(const void *data)
{
	int t1, t2;

	t1 = ri.Milliseconds ();

	if(!r_smp->integer || data == backEndData[0]->commands.cmds){
		backEnd.smpFrame = 0;
	}else{
		backEnd.smpFrame = 1;
	}

	while(1){
		data = PADP(data, sizeof(void *));

		switch(*(const int*)data){
		case RC_SET_COLOR:
			data = RB_SetColor(data);
			break;
		case RC_STRETCH_PIC:
			data = RB_StretchPic(data);
			break;
		case RC_DRAW_SURFS:
			data = RB_DrawSurfs(data);
			break;
		case RC_DRAW_BUFFER:
			data = RB_DrawBuffer(data);
			break;
		case RC_SWAP_BUFFERS:
			data = RB_SwapBuffers(data);
			break;
		case RC_SCREENSHOT:
			data = RB_TakeScreenshotCmd(data);
			break;
		case RC_VIDEOFRAME:
			data = RB_TakeVideoFrameCmd(data);
			break;
		case RC_COLORMASK:
			data = RB_ColorMask(data);
			break;
		case RC_CLEARDEPTH:
			data = RB_ClearDepth(data);
			break;
		case RC_CAPSHADOWMAP:
			data = RB_CapShadowMap(data);
			break;
		case RC_POSTPROCESS:
			data = RB_PostProcess(data);
			break;
		case RC_END_OF_LIST:
		default:
			/* stop rendering on this thread */
			t2 = ri.Milliseconds ();
			backEnd.pc.msec = t2 - t1;
			return;
		}
	}

}
Example #3
0
/*
====================
RB_ExecuteRenderCommands
====================
*/
void RB_ExecuteRenderCommands( const void *data ) {
	int		t1, t2;

	t1 = ri.Milliseconds ();

	while ( 1 ) {
		data = PADP(data, sizeof(void *));

		switch ( *(const int *)data ) {
		case RC_SET_COLOR:
			data = RB_SetColor( data );
			break;
		case RC_STRETCH_PIC:
			data = RB_StretchPic( data );
			break;
		case RC_DRAW_SURFS:
			data = RB_DrawSurfs( data );
			break;
		case RC_DRAW_BUFFER:
			data = RB_DrawBuffer( data );
			break;
		case RC_SWAP_BUFFERS:
			data = RB_SwapBuffers( data );
			break;
		case RC_SCREENSHOT:
			data = RB_TakeScreenshotCmd( data );
			break;
		case RC_VIDEOFRAME:
			data = RB_TakeVideoFrameCmd( data );
			break;
		case RC_COLORMASK:
			data = RB_ColorMask(data);
			break;
		case RC_CLEARDEPTH:
			data = RB_ClearDepth(data);
			break;
		case RC_CAPSHADOWMAP:
			data = RB_CapShadowMap(data);
			break;
		case RC_POSTPROCESS:
			data = RB_PostProcess(data);
			break;
		case RC_EXPORT_CUBEMAPS:
			data = RB_ExportCubemaps(data);
			break;
		case RC_END_OF_LIST:
		default:
			// finish any 2D drawing if needed
			if(tess.numIndexes)
				RB_EndSurface();

			// stop rendering
			t2 = ri.Milliseconds ();
			backEnd.pc.msec = t2 - t1;
			return;
		}
	}

}
Example #4
0
/*
====================
RB_ExecuteRenderCommands
====================
*/
void RB_ExecuteRenderCommands( const void *data ) {
	int		t1, t2;

	t1 = ri.Milliseconds ();

	while ( 1 ) {
		data = PADP(data, sizeof(void *));

		switch ( *(const int *)data ) {
		case RC_SET_COLOR:
			data = RB_SetColor( data );
			break;
		case RC_STRETCH_PIC:
			data = RB_StretchPic( data );
			break;
		case RC_ROTATED_PIC:
			data = RB_RotatedPic( data );
			break;
		case RC_DRAW_SURFS:
			data = RB_DrawSurfs( data );
			break;
		case RC_DRAW_BUFFER:
			data = RB_DrawBuffer( data );
			break;
		case RC_SWAP_BUFFERS:
			data = RB_SwapBuffers( data );
			break;
		case RC_SCREENSHOT:
			data = RB_TakeScreenshotCmd( data );
			break;
		case RC_VIDEOFRAME:
			data = RB_TakeVideoFrameCmd( data );
			break;
		case RC_COLORMASK:
			data = RB_ColorMask(data);
			break;
		case RC_CLEARDEPTH:
			data = RB_ClearDepth(data);
			break;
		case RC_END_OF_LIST:
		default:
			// stop rendering
			t2 = ri.Milliseconds ();
			backEnd.pc.msec = t2 - t1;
			return;
		}
	}

}
Example #5
0
byte* RB_ReadPixels(int x, int y, int width, int height, size_t* offset, int* padlen) {
    byte* buffer, *bufstart;
    int padwidth, linelen;
    GLint packAlign;

    qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);

    linelen = width * 3;
    padwidth = PAD(linelen, packAlign);

    // Allocate a few more bytes so that we can choose an alignment we like
    buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1);

    bufstart = PADP((intptr_t) buffer + *offset, packAlign);
    qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart);

    *offset = bufstart - buffer;
    *padlen = padwidth - linelen;

    return buffer;
}
Example #6
0
byte *RB_ReadZBuffer(int x, int y, int width, int height, int *padlen)
{
	byte  *buffer, *bufstart;
	int   padwidth, linelen;
	GLint packAlign;

	qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);

	linelen  = width;
	padwidth = PAD(linelen, packAlign);

	// Allocate a few more bytes so that we can choose an alignment we like
	buffer = ri.Hunk_AllocateTempMemory(padwidth * height + packAlign - 1);

	bufstart = PADP(( intptr_t ) buffer, packAlign);
	qglDepthRange(0.0f, 1.0f);
	memset(buffer, 0, padwidth * height + packAlign - 1);   //*TODO* find something to read DepthBuffer ?!

	*padlen = padwidth - linelen;

	return buffer;
}
Example #7
0
byte *RB_ReadZBuffer(int x, int y, int width, int height, int *padlen)
{
	byte  *buffer, *bufstart;
	int   padwidth, linelen;
	GLint packAlign;

	qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);

	linelen  = width;
	padwidth = PAD(linelen, packAlign);

	// Allocate a few more bytes so that we can choose an alignment we like
	buffer = ri.Hunk_AllocateTempMemory(padwidth * height + packAlign - 1);

	bufstart = PADP(( intptr_t ) buffer, packAlign);
	qglDepthRange(0.0f, 1.0f);
	qglReadPixels(x, y, width, height, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, bufstart);

	*padlen = padwidth - linelen;

	return buffer;
}
Example #8
0
byte *RB_ReadPixels(int x, int y, int width, int height, size_t *offset, int *padlen)
{
	byte *buffer, *bufstart;
	int padwidth, linelen;
	GLint packAlign;
	
	qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);
	
	linelen = width * 3;
	padwidth = PAD(linelen, packAlign);
	
	// Allocate a few more bytes so that we can choose an alignment we like
	buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1);

#ifdef USE_OPENGLES
	bufstart=buffer;
	padwidth=linelen;
	int p2width=1, p2height=1;
	int xx, yy, aa;
	while (p2width<glConfig.vidWidth) p2width*=2;
	while (p2height<glConfig.vidHeight) p2height*=2;
	byte *source = (byte*) ri.Z_Malloc( p2width * p2height * 4 );
	qglReadPixels( 0, 0, p2width, p2height, GL_RGBA, GL_UNSIGNED_BYTE, source );
	for (yy=y; yy<height; yy++)
		for (xx=x; xx<width; xx++)
			for (aa=0; aa<3; aa++)
				buffer[yy*width*3+xx*3+aa]=source[(yy+y)*p2width*4+(xx+x)*4+aa];
	ri.Free(source);
#else
	bufstart = PADP((intptr_t) buffer + *offset, packAlign);
	qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart);
#endif
	
	*offset = bufstart - buffer;
	*padlen = padwidth - linelen;
	
	return buffer;
}
Example #9
0
/*
==================
RB_TakeVideoFrameCmd
==================
*/
const void *RB_TakeVideoFrameCmd( const void *data )
{
	const videoFrameCommand_t	*cmd;
	byte				*cBuf;
	size_t				memcount, linelen;
	int				padwidth, avipadwidth, padlen, avipadlen;
	GLint packAlign;
	
	cmd = (const videoFrameCommand_t *)data;
	
	qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);

	linelen = cmd->width * 3;

	// Alignment stuff for glReadPixels
	padwidth = PAD(linelen, packAlign);
	padlen = padwidth - linelen;
	// AVI line padding
	avipadwidth = PAD(linelen, AVI_LINE_PADDING);
	avipadlen = avipadwidth - linelen;

	cBuf = PADP(cmd->captureBuffer, packAlign);
		
	qglReadPixels(0, 0, cmd->width, cmd->height, GL_RGB,
		GL_UNSIGNED_BYTE, cBuf);

	memcount = padwidth * cmd->height;

	// gamma correct
	if(glConfig.deviceSupportsGamma)
		R_GammaCorrect(cBuf, memcount);

	if(cmd->motionJpeg)
	{
		memcount = RE_SaveJPGToBuffer(cmd->encodeBuffer, linelen * cmd->height,
			r_aviMotionJpegQuality->integer,
			cmd->width, cmd->height, cBuf, padlen);
		ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, memcount);
	}
	else
	{
		byte *lineend, *memend;
		byte *srcptr, *destptr;
	
		srcptr = cBuf;
		destptr = cmd->encodeBuffer;
		memend = srcptr + memcount;
		
		// swap R and B and remove line paddings
		while(srcptr < memend)
		{
			lineend = srcptr + linelen;
			while(srcptr < lineend)
			{
				*destptr++ = srcptr[2];
				*destptr++ = srcptr[1];
				*destptr++ = srcptr[0];
				srcptr += 3;
			}
			
			Com_Memset(destptr, '\0', avipadlen);
			destptr += avipadlen;
			
			srcptr += padlen;
		}
		
		ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, avipadwidth * cmd->height);
	}

	return (const void *)(cmd + 1);	
}
Example #10
0
/*
==================
RB_TakeVideoFrameCmd
==================
*/
const void     *RB_TakeVideoFrameCmd( const void *data )
{
	const videoFrameCommand_t *cmd;
	GLint                     packAlign;
	int                       lineLen, captureLineLen;
	byte                      *pixels;
	int                       i;
	int                       outputSize;
	int                       j;
	int                       aviLineLen;

	cmd = ( const videoFrameCommand_t * ) data;

	// RB: it is possible to we still have a videoFrameCommand_t but we already stopped
	// video recording
	if ( ri.CL_VideoRecording() )
	{
		// take care of alignment issues for reading RGB images..

		glGetIntegerv( GL_PACK_ALIGNMENT, &packAlign );

		lineLen = cmd->width * 3;
		captureLineLen = PAD( lineLen, packAlign );

		pixels = ( byte * ) PADP( cmd->captureBuffer, packAlign );
		glReadPixels( 0, 0, cmd->width, cmd->height, GL_RGB, GL_UNSIGNED_BYTE, pixels );

		if ( tr.overbrightBits > 0 && glConfig.deviceSupportsGamma )
		{
			// this also runs over the padding...
			R_GammaCorrect( pixels, captureLineLen * cmd->height );
		}

		if ( cmd->motionJpeg )
		{
			// Drop alignment and line padding bytes
			for ( i = 0; i < cmd->height; ++i )
			{
				memmove( cmd->captureBuffer + i * lineLen, pixels + i * captureLineLen, lineLen );
			}

			outputSize = SaveJPGToBuffer( cmd->encodeBuffer, 3 * cmd->width * cmd->height, 90, cmd->width, cmd->height, cmd->captureBuffer );
			ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, outputSize );
		}
		else
		{
			aviLineLen = PAD( lineLen, AVI_LINE_PADDING );

			for ( i = 0; i < cmd->height; ++i )
			{
				for ( j = 0; j < lineLen; j += 3 )
				{
					cmd->encodeBuffer[ i * aviLineLen + j + 0 ] = pixels[ i * captureLineLen + j + 2 ];
					cmd->encodeBuffer[ i * aviLineLen + j + 1 ] = pixels[ i * captureLineLen + j + 1 ];
					cmd->encodeBuffer[ i * aviLineLen + j + 2 ] = pixels[ i * captureLineLen + j + 0 ];
				}

				while ( j < aviLineLen )
				{
					cmd->encodeBuffer[ i * aviLineLen + j++ ] = 0;
				}
			}

			ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, aviLineLen * cmd->height );
		}
	}

	return ( const void * )( cmd + 1 );
}
/*
====================
RB_ExecuteRenderCommands

This function will be called synchronously if running without
smp extensions, or asynchronously by another thread.
====================
*/
void RB_ExecuteRenderCommands( const void *data ) {
	int		t1, t2;

	t1 = ri.Milliseconds ();

	if ( !r_smp->integer || data == backEndData[0]->commands.cmds ) {
		backEnd.smpFrame = 0;
	} else {
		backEnd.smpFrame = 1;
	}

	while ( 1 ) {
		data = PADP(data, sizeof(void *));

		switch ( *(const int *)data ) {
		case RC_SET_COLOR:
			data = RB_SetColor( data );
			break;
		case RC_STRETCH_PIC:
#ifdef FRAMEBUFFER_AND_GLSL_SUPPORT
			R_FrameBuffer_EndFrame();
#endif
			data = RB_StretchPic( data );
			break;
		case RC_DRAW_SURFS:
			data = RB_DrawSurfs( data );
			break;
		case RC_DRAW_BUFFER:
#ifdef FRAMEBUFFER_AND_GLSL_SUPPORT
			data = useFrameBuffer ? RB_DrawFrameBuffer( data ) : RB_DrawBuffer( data );
#else
			data = RB_DrawBuffer( data );
#endif
			break;
		case RC_SWAP_BUFFERS:
			data = RB_SwapBuffers( data );
			break;
		//these two use a hack to let them copy the framebuffer effects too
		case RC_SCREENSHOT:
#ifdef FRAMEBUFFER_AND_GLSL_SUPPORT
			R_FrameBufferUnBind();
#endif
			data = RB_TakeScreenshotCmd( data );
#ifdef FRAMEBUFFER_AND_GLSL_SUPPORT
			R_FrameBufferBind();
#endif
			break;
		case RC_VIDEOFRAME:
#ifdef FRAMEBUFFER_AND_GLSL_SUPPORT
			R_FrameBufferUnBind();
#endif
			data = RB_TakeVideoFrameCmd( data );
#ifdef FRAMEBUFFER_AND_GLSL_SUPPORT
			R_FrameBufferBind();
#endif
			break;
		case RC_COLORMASK:
			data = RB_ColorMask(data);
			break;
		case RC_CLEARDEPTH:
			data = RB_ClearDepth(data);
			break;
		case RC_END_OF_LIST:
		default:
			// stop rendering on this thread
			t2 = ri.Milliseconds ();
			backEnd.pc.msec = t2 - t1;
			return;
		}
	}

}
Example #12
0
/*
=================
R_LoadIQModel

Load an IQM model and compute the joint matrices for every frame.
=================
*/
bool R_LoadIQModel( model_t *mod, void *buffer, int filesize,
			const char *mod_name ) {
	iqmHeader_t		*header;
	iqmVertexArray_t	*vertexarray;
	iqmTriangle_t		*triangle;
	iqmMesh_t		*mesh;
	iqmJoint_t		*joint;
	iqmPose_t		*pose;
	iqmAnim_t		*anim;
	unsigned short		*framedata;
	char			*str, *name;
	int		len;
	transform_t		*trans, *poses;
	float			*bounds;
	size_t			size, len_names;
	IQModel_t		*IQModel;
	IQAnim_t		*IQAnim;
	srfIQModel_t		*surface;
	vboData_t               vboData;
	float                   *weightbuf;
	int                     *indexbuf;
	i16vec4_t               *qtangentbuf;
	VBO_t                   *vbo;
	IBO_t                   *ibo;
	void                    *ptr;
	u8vec4_t                *weights;

	if( !LoadIQMFile( buffer, filesize, mod_name, &len_names ) ) {
		return false;
	}

	header = (iqmHeader_t *)buffer;

	// compute required space
	size = sizeof(IQModel_t);
	size += header->num_meshes * sizeof( srfIQModel_t );
	size += header->num_anims * sizeof( IQAnim_t );
	size += header->num_joints * sizeof( transform_t );
	size = PAD( size, 16 );
	size += header->num_joints * header->num_frames * sizeof( transform_t );
	if(header->ofs_bounds)
		size += header->num_frames * 6 * sizeof(float);	// model bounds
	size += header->num_vertexes * 3 * sizeof(float);	// positions
	size += header->num_vertexes * 3 * sizeof(float);	// normals
	size += header->num_vertexes * 3 * sizeof(float);	// tangents
	size += header->num_vertexes * 3 * sizeof(float);	// bitangents
	size += header->num_vertexes * 2 * sizeof(int16_t);	// texcoords
	size += header->num_vertexes * 4 * sizeof(byte);	// blendIndexes
	size += header->num_vertexes * 4 * sizeof(byte);	// blendWeights
	size += header->num_vertexes * 4 * sizeof(byte);	// colors
	size += header->num_triangles * 3 * sizeof(int);	// triangles
	size += header->num_joints * sizeof(int);		// parents
	size += len_names;					// joint and anim names

	IQModel = (IQModel_t *)ri.Hunk_Alloc( size, ha_pref::h_low );
	mod->type = modtype_t::MOD_IQM;
	mod->iqm = IQModel;
	ptr = IQModel + 1;

	// fill header and setup pointers
	IQModel->num_vertexes = header->num_vertexes;
	IQModel->num_triangles = header->num_triangles;
	IQModel->num_frames   = header->num_frames;
	IQModel->num_surfaces = header->num_meshes;
	IQModel->num_joints   = header->num_joints;
	IQModel->num_anims    = header->num_anims;

	IQModel->surfaces = (srfIQModel_t *)ptr;
	ptr = IQModel->surfaces + header->num_meshes;

	if( header->ofs_anims ) {
		IQModel->anims = (IQAnim_t *)ptr;
		ptr = IQModel->anims + header->num_anims;
	} else {
		IQModel->anims = nullptr;
	}

	IQModel->joints = (transform_t *)PADP(ptr, 16);
	ptr = IQModel->joints + header->num_joints;

	if( header->ofs_poses ) {
		poses = (transform_t *)ptr;
		ptr = poses + header->num_poses * header->num_frames;
	} else {
		poses = nullptr;
	}

	if( header->ofs_bounds ) {
		bounds = (float *)ptr;
		ptr = bounds + 6 * header->num_frames;
	} else {
		bounds = nullptr;
	}

	IQModel->positions = (float *)ptr;
	ptr = IQModel->positions + 3 * header->num_vertexes;

	IQModel->normals = (float *)ptr;
	ptr = IQModel->normals + 3 * header->num_vertexes;

	IQModel->tangents = (float *)ptr;
	ptr = IQModel->tangents + 3 * header->num_vertexes;

	IQModel->bitangents = (float *)ptr;
	ptr = IQModel->bitangents + 3 * header->num_vertexes;

	IQModel->texcoords = (int16_t *)ptr;
	ptr = IQModel->texcoords + 2 * header->num_vertexes;

	IQModel->blendIndexes = (byte *)ptr;
	ptr = IQModel->blendIndexes + 4 * header->num_vertexes;

	IQModel->blendWeights = (byte *)ptr;
	ptr = IQModel->blendWeights + 4 * header->num_vertexes;

	IQModel->colors = (byte *)ptr;
	ptr = IQModel->colors + 4 * header->num_vertexes;

	IQModel->jointParents = (int *)ptr;
	ptr = IQModel->jointParents + header->num_joints;

	IQModel->triangles = (int *)ptr;
	ptr = IQModel->triangles + 3 * header->num_triangles;

	str                   = (char *)ptr;
	IQModel->jointNames   = str;

	// copy joint names
	joint = ( iqmJoint_t* )IQMPtr( header, header->ofs_joints );
	for(unsigned i = 0; i < header->num_joints; i++, joint++ ) {
		name = ( char* )IQMPtr( header, header->ofs_text + joint->name );
		len = strlen( name ) + 1;
		Com_Memcpy( str, name, len );
		str += len;
	}

	// setup animations
	IQAnim = IQModel->anims;
	anim = ( iqmAnim_t* )IQMPtr( header, header->ofs_anims );
	for(int i = 0; i < IQModel->num_anims; i++, IQAnim++, anim++ ) {
		IQAnim->num_frames   = anim->num_frames;
		IQAnim->framerate    = anim->framerate;
		IQAnim->num_joints   = header->num_joints;
		IQAnim->flags        = anim->flags;
		IQAnim->jointParents = IQModel->jointParents;
		if( poses ) {
			IQAnim->poses    = poses + anim->first_frame * header->num_poses;
		} else {
			IQAnim->poses    = nullptr;
		}
		if( bounds ) {
			IQAnim->bounds   = bounds + anim->first_frame * 6;
		} else {
			IQAnim->bounds    = nullptr;
		}
		IQAnim->name         = str;
		IQAnim->jointNames   = IQModel->jointNames;

		name = ( char* )IQMPtr( header, header->ofs_text + anim->name );
		len = strlen( name ) + 1;
		Com_Memcpy( str, name, len );
		str += len;
	}

	// calculate joint transforms
	trans = IQModel->joints;
	joint = ( iqmJoint_t* )IQMPtr( header, header->ofs_joints );
	for(unsigned i = 0; i < header->num_joints; i++, joint++, trans++ ) {
		if( joint->parent >= (int) i ) {
			Log::Warn("R_LoadIQModel: file %s contains an invalid parent joint number.",
				  mod_name );
			return false;
		}

		TransInitRotationQuat( joint->rotate, trans );
		TransAddScale( joint->scale[0], trans );
		TransAddTranslation( joint->translate, trans );

		if( joint->parent >= 0 ) {
			TransCombine( trans, &IQModel->joints[ joint->parent ],
				      trans );
		}

		IQModel->jointParents[i] = joint->parent;
	}

	// calculate pose transforms
	framedata = ( short unsigned int* )IQMPtr( header, header->ofs_frames );
	trans = poses;
	for(unsigned i = 0; i < header->num_frames; i++ ) {
		pose = ( iqmPose_t* )IQMPtr( header, header->ofs_poses );
		for(unsigned j = 0; j < header->num_poses; j++, pose++, trans++ ) {
			vec3_t	translate;
			quat_t	rotate;
			vec3_t	scale;

			translate[0] = pose->channeloffset[0];
			if( pose->mask & 0x001)
				translate[0] += *framedata++ * pose->channelscale[0];
			translate[1] = pose->channeloffset[1];
			if( pose->mask & 0x002)
				translate[1] += *framedata++ * pose->channelscale[1];
			translate[2] = pose->channeloffset[2];
			if( pose->mask & 0x004)
				translate[2] += *framedata++ * pose->channelscale[2];
			rotate[0] = pose->channeloffset[3];
			if( pose->mask & 0x008)
				rotate[0] += *framedata++ * pose->channelscale[3];
			rotate[1] = pose->channeloffset[4];
			if( pose->mask & 0x010)
				rotate[1] += *framedata++ * pose->channelscale[4];
			rotate[2] = pose->channeloffset[5];
			if( pose->mask & 0x020)
				rotate[2] += *framedata++ * pose->channelscale[5];
			rotate[3] = pose->channeloffset[6];
			if( pose->mask & 0x040)
				rotate[3] += *framedata++ * pose->channelscale[6];
			scale[0] = pose->channeloffset[7];
			if( pose->mask & 0x080)
				scale[0] += *framedata++ * pose->channelscale[7];
			scale[1] = pose->channeloffset[8];
			if( pose->mask & 0x100)
				scale[1] += *framedata++ * pose->channelscale[8];
			scale[2] = pose->channeloffset[9];
			if( pose->mask & 0x200)
				scale[2] += *framedata++ * pose->channelscale[9];

			if( scale[0] < 0.0f ||
			    (int)( scale[0] - scale[1] ) ||
			    (int)( scale[1] - scale[2] ) ) {
				Log::Warn("R_LoadIQM: file %s contains an invalid scale.", mod_name );
				return false;
			    }

			// construct transformation
			TransInitRotationQuat( rotate, trans );
			TransAddScale( scale[0], trans );
			TransAddTranslation( translate, trans );
		}
	}

	// copy vertexarrays and indexes
	vertexarray = ( iqmVertexArray_t* )IQMPtr( header, header->ofs_vertexarrays );
	for(unsigned i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) {
		int	n;

		// total number of values
		n = header->num_vertexes * vertexarray->size;

		switch( vertexarray->type ) {
		case IQM_POSITION:
			ClearBounds( IQModel->bounds[ 0 ], IQModel->bounds[ 1 ] );
			Com_Memcpy( IQModel->positions,
				    IQMPtr( header, vertexarray->offset ),
				    n * sizeof(float) );
			for( int j = 0; j < n; j += vertexarray->size ) {
				AddPointToBounds( &IQModel->positions[ j ],
						  IQModel->bounds[ 0 ],
						  IQModel->bounds[ 1 ] );
			}
			IQModel->internalScale = BoundsMaxExtent( IQModel->bounds[ 0 ], IQModel->bounds[ 1 ] );
			if( IQModel->internalScale > 0.0f ) {
				float inverseScale = 1.0f / IQModel->internalScale;
				for( int j = 0; j < n; j += vertexarray->size ) {
					VectorScale( &IQModel->positions[ j ],
						     inverseScale,
						     &IQModel->positions[ j ] );
				}
			}

			break;
		case IQM_NORMAL:
			Com_Memcpy( IQModel->normals,
				    IQMPtr( header, vertexarray->offset ),
				    n * sizeof(float) );
			break;
		case IQM_TANGENT:
			BuildTangents( header->num_vertexes,
				       ( float* )IQMPtr( header, vertexarray->offset ),
				       IQModel->normals, IQModel->tangents,
				       IQModel->bitangents );
			break;
		case IQM_TEXCOORD:
			for( int j = 0; j < n; j++ ) {
				IQModel->texcoords[ j ] = floatToHalf( ((float *)IQMPtr( header, vertexarray->offset ))[ j ] );
			}
			break;
		case IQM_BLENDINDEXES:
			Com_Memcpy( IQModel->blendIndexes,
				    IQMPtr( header, vertexarray->offset ),
				    n * sizeof(byte) );
			break;
		case IQM_BLENDWEIGHTS:
			weights = (u8vec4_t *)IQMPtr( header, vertexarray->offset );
			for(unsigned j = 0; j < header->num_vertexes; j++ ) {
				IQModel->blendWeights[ 4 * j + 0 ] = 255 - weights[ j ][ 1 ] - weights[ j ][ 2 ] - weights[ j ][ 3 ];
				IQModel->blendWeights[ 4 * j + 1 ] = weights[ j ][ 1 ];
				IQModel->blendWeights[ 4 * j + 2 ] = weights[ j ][ 2 ];
				IQModel->blendWeights[ 4 * j + 3 ] = weights[ j ][ 3 ];
			}
			break;
		case IQM_COLOR:
			Com_Memcpy( IQModel->colors,
				    IQMPtr( header, vertexarray->offset ),
				    n * sizeof(byte) );
			break;
		}
	}

	// copy triangles
	triangle = ( iqmTriangle_t* )IQMPtr( header, header->ofs_triangles );
	for(unsigned i = 0; i < header->num_triangles; i++, triangle++ ) {
		IQModel->triangles[3*i+0] = triangle->vertex[0];
		IQModel->triangles[3*i+1] = triangle->vertex[1];
		IQModel->triangles[3*i+2] = triangle->vertex[2];
	}

	// convert data where necessary and create VBO
	if( r_vboModels->integer && glConfig2.vboVertexSkinningAvailable
	    && IQModel->num_joints <= glConfig2.maxVertexSkinningBones ) {

		if( IQModel->blendIndexes ) {
			indexbuf = (int *)ri.Hunk_AllocateTempMemory( sizeof(int[4]) * IQModel->num_vertexes );
			for(int i = 0; i < IQModel->num_vertexes; i++ ) {
				indexbuf[ 4 * i + 0 ] = IQModel->blendIndexes[ 4 * i + 0 ];
				indexbuf[ 4 * i + 1 ] = IQModel->blendIndexes[ 4 * i + 1 ];
				indexbuf[ 4 * i + 2 ] = IQModel->blendIndexes[ 4 * i + 2 ];
				indexbuf[ 4 * i + 3 ] = IQModel->blendIndexes[ 4 * i + 3 ];
			}
		} else {
			indexbuf = nullptr;
		}
		if( IQModel->blendWeights ) {
			const float weightscale = 1.0f / 255.0f;

			weightbuf = (float *)ri.Hunk_AllocateTempMemory( sizeof(vec4_t) * IQModel->num_vertexes );
			for(int i = 0; i < IQModel->num_vertexes; i++ ) {
				if( IQModel->blendWeights[ 4 * i + 0 ] == 0 &&
				    IQModel->blendWeights[ 4 * i + 1 ] == 0 &&
				    IQModel->blendWeights[ 4 * i + 2 ] == 0 &&
				    IQModel->blendWeights[ 4 * i + 3 ] == 0 )
					IQModel->blendWeights[ 4 * i + 0 ] = 255;

				weightbuf[ 4 * i + 0 ] = weightscale * IQModel->blendWeights[ 4 * i + 0 ];
				weightbuf[ 4 * i + 1 ] = weightscale * IQModel->blendWeights[ 4 * i + 1 ];
				weightbuf[ 4 * i + 2 ] = weightscale * IQModel->blendWeights[ 4 * i + 2 ];
				weightbuf[ 4 * i + 3 ] = weightscale * IQModel->blendWeights[ 4 * i + 3 ];
			}
		} else {
			weightbuf = nullptr;
		}

		qtangentbuf = (i16vec4_t *)ri.Hunk_AllocateTempMemory( sizeof( i16vec4_t ) * IQModel->num_vertexes );

		for(int i = 0; i < IQModel->num_vertexes; i++ ) {
			R_TBNtoQtangents( &IQModel->tangents[ 3 * i ],
					  &IQModel->bitangents[ 3 * i ],
					  &IQModel->normals[ 3 * i ],
					  qtangentbuf[ i ] );
		}

		vboData.xyz = (vec3_t *)IQModel->positions;
		vboData.qtangent = qtangentbuf;
		vboData.numFrames = 0;
		vboData.color = (u8vec4_t *)IQModel->colors;
		vboData.st = (i16vec2_t *)IQModel->texcoords;
		vboData.noLightCoords = true;
		vboData.boneIndexes = (int (*)[4])indexbuf;
		vboData.boneWeights = (vec4_t *)weightbuf;
		vboData.numVerts = IQModel->num_vertexes;


		vbo = R_CreateStaticVBO( "IQM surface VBO", vboData,
					 vboLayout_t::VBO_LAYOUT_SKELETAL );

		if( qtangentbuf ) {
			ri.Hunk_FreeTempMemory( qtangentbuf );
		}
		if( weightbuf ) {
			ri.Hunk_FreeTempMemory( weightbuf );
		}
		if( indexbuf ) {
			ri.Hunk_FreeTempMemory( indexbuf );
		}

		// create IBO
		ibo = R_CreateStaticIBO( "IQM surface IBO", ( glIndex_t* )IQModel->triangles, IQModel->num_triangles * 3 );
	} else {
		vbo = nullptr;
		ibo = nullptr;
	}

	// register shaders
	// overwrite the material offset with the shader index
	mesh = ( iqmMesh_t* )IQMPtr( header, header->ofs_meshes );
	surface = IQModel->surfaces;
	for(unsigned i = 0; i < header->num_meshes; i++, mesh++, surface++ ) {
		surface->surfaceType = surfaceType_t::SF_IQM;

		if( mesh->name ) {
			surface->name = str;
			name = ( char* )IQMPtr( header, header->ofs_text + mesh->name );
			len = strlen( name ) + 1;
			Com_Memcpy( str, name, len );
			str += len;
		} else {
			surface->name = nullptr;
		}

		surface->shader = R_FindShader( ( char* )IQMPtr(header, header->ofs_text + mesh->material),
						shaderType_t::SHADER_3D_DYNAMIC, RSF_DEFAULT );
		if( surface->shader->defaultShader )
			surface->shader = tr.defaultShader;
		surface->data = IQModel;
		surface->first_vertex = mesh->first_vertex;
		surface->num_vertexes = mesh->num_vertexes;
		surface->first_triangle = mesh->first_triangle;
		surface->num_triangles = mesh->num_triangles;
		surface->vbo = vbo;
		surface->ibo = ibo;
	}

	// copy model bounds
	if(header->ofs_bounds)
	{
		iqmBounds_t *ptr = ( iqmBounds_t* )IQMPtr( header, header->ofs_bounds );
		for(unsigned i = 0; i < header->num_frames; i++)
		{
			VectorCopy( ptr->bbmin, bounds );
			bounds += 3;
			VectorCopy( ptr->bbmax, bounds );
			bounds += 3;

			ptr++;
		}
	}

	// register animations
	IQAnim = IQModel->anims;
	if( header->num_anims == 1 ) {
		RE_RegisterAnimationIQM( mod_name, IQAnim );
	}
	for(unsigned i = 0; i < header->num_anims; i++, IQAnim++ ) {
		char name[ MAX_QPATH ];

		Com_sprintf( name, MAX_QPATH, "%s:%s", mod_name, IQAnim->name );
		RE_RegisterAnimationIQM( name, IQAnim );
	}

	// build VBO

	return true;
}
Example #13
0
/*
====================
R_LevelShot

levelshots are specialized 128*128 thumbnails for
the menu system, sampled down from full screen distorted images
====================
*/
void R_LevelShot( screenshotType_e type, const char *ext ) {
	char		fileName[MAX_OSPATH];
	byte		*source;
	byte		*resample, *resamplestart;
	size_t		offset = 0, memcount;
	int			spadlen, rpadlen;
	int			padwidth, linelen;
	GLint		packAlign;
	byte		*src, *dst;
	int			x, y;
	int			r, g, b;
	float		xScale, yScale;
	int			xx, yy;
	int			width, height;
	int			arg;

	// Allow custom resample width/height
	arg = atoi(ri.Cmd_Argv(2));
	if (arg > 0)
		width = height = arg;
	else
		width = height = 128;

	if (width > glConfig.vidWidth)
		width = glConfig.vidWidth;
	if (height > glConfig.vidHeight)
		height = glConfig.vidHeight;

	Com_sprintf(fileName, sizeof(fileName), "levelshots/%s_small%s", tr.world->baseName, ext);

	source = RB_ReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, &offset, &spadlen);

	//
	// Based on RB_ReadPixels
	qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);

	linelen = width * 3;
	padwidth = PAD(linelen, packAlign);

	// Allocate a few more bytes so that we can choose an alignment we like
	resample = ri.Hunk_AllocateTempMemory(padwidth * height + offset + packAlign - 1);

	resamplestart = PADP((intptr_t) resample + offset, packAlign);

	offset = resamplestart - resample;
	rpadlen = padwidth - linelen;
	//

	// resample from source
	xScale = glConfig.vidWidth / (float)(width * 4.0f);
	yScale = glConfig.vidHeight / (float)(height * 3.0f);
	for ( y = 0 ; y < height ; y++ ) {
		for ( x = 0 ; x < width ; x++ ) {
			r = g = b = 0;
			for ( yy = 0 ; yy < 3 ; yy++ ) {
				for ( xx = 0 ; xx < 4 ; xx++ ) {
					src = source + (3 * glConfig.vidWidth + spadlen) * (int)((y*3 + yy) * yScale) +
						3 * (int) ((x*4 + xx) * xScale);
					r += src[0];
					g += src[1];
					b += src[2];
				}
			}
			dst = resample + 3 * ( y * width + x );
			dst[0] = r / 12;
			dst[1] = g / 12;
			dst[2] = b / 12;
		}
	}

	memcount = (width * 3 + rpadlen) * height;

	// gamma correct
	if(glConfig.deviceSupportsGamma)
		R_GammaCorrect(resample + offset, memcount);

	if ( type == ST_TGA )
		RE_SaveTGA(fileName, width, height, resample + offset, rpadlen);
	else if ( type == ST_JPEG )
		RE_SaveJPG(fileName, r_screenshotJpegQuality->integer, width, height, resample + offset, rpadlen);
	else if ( type == ST_PNG )
		RE_SavePNG(fileName, width, height, resample + offset, rpadlen);

	ri.Hunk_FreeTempMemory(resample);
	ri.Hunk_FreeTempMemory(source);

	ri.Printf( PRINT_ALL, "Wrote %s\n", fileName );
}