Beispiel #1
0
/*
* R_FreeCinematic
*/
void R_FreeCinematic( unsigned int id )
{
	r_cinhandle_t *handle;
	
	handle = R_GetCinematicHandleById( id );
	if( !handle ) {
		return;
	}

	ri.CIN_Close( handle->cin );
	handle->cin = NULL;

	assert( handle->name );
	R_Free( handle->name );
	handle->name = NULL;

	assert( handle->uploadName );
	R_Free( handle->uploadName );
	handle->uploadName = NULL;

	// remove from linked active list
	handle->prev->next = handle->next;
	handle->next->prev = handle->prev;

	// insert into linked free list
	handle->next = r_free_cinematics;
	r_free_cinematics = handle;
}
Beispiel #2
0
/*
* SkinFile_FreeSkinFile
*/
static void SkinFile_FreeSkinFile( skinfile_t *skinfile ) {
	int i;

	if( skinfile->numpairs ) {
		for( i = 0; i < skinfile->numpairs; i++ )
			R_Free( skinfile->pairs[i].meshname );
		R_Free( skinfile->pairs );
	}

	R_Free( skinfile->name );

	memset( skinfile, 0, sizeof( skinfile_t ) );
}
Beispiel #3
0
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
permuto will return a vector of all permutations needed for bruvo's distance.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
SEXP permuto(SEXP perm)
{
	int permutations;
	int i;
	int per;
	SEXP Rval;
	/* 
		IMPORTANT: INITIALIZE THE COUNTER. THE POINTER IS NOT RELEASED FROM
		MEMORY OTHERWISE.
	*/
	perm_count = 0;
	perm = coerceVector(perm, INTSXP);
	per = INTEGER(perm)[0];
	int *allele_array;
	allele_array = R_Calloc(per, int);
	permutations = fact(per)*per;
	for(i = 0; i < per; i++)
	{
		allele_array[i] = i;
	}
	PROTECT(Rval = allocVector(INTSXP, permutations));
	permute(allele_array, 0, per-1, INTEGER(Rval));
	UNPROTECT(1);
	R_Free(allele_array);
	return Rval;
}
Beispiel #4
0
SEXP dotask(SEXP Sclient, SEXP Sfun, SEXP Swork, SEXP Suval, SEXP Sback, SEXP Shigh){
   rgearman_client_t *client = (rgearman_client_t *)R_ExternalPtrAddr(Sclient);
   SEXP ret;
   const char *fun, *work, *uval;
   int back, high;

   fun = (Sfun != R_NilValue)? (const char *)CHAR(STRING_ELT(Sfun,0)) : NULL;
   work = (Swork != R_NilValue)? (const char *)CHAR(STRING_ELT(Swork,0)) : NULL;
   uval = (Suval != R_NilValue)? (const char *)CHAR(STRING_ELT(Suval,0)) : NULL;

   back = LOGICAL(Sback)[0];
   high = (Shigh != R_NilValue) ? LOGICAL(Shigh)[0] : -1;

   if (back){
      gearman_return_t (*gm_fun)(gearman_client_st *client, const char *function_name, const char *unique, const void *workload, size_t workload_size, gearman_job_handle_t job_handle); 
      char *job = (char *)R_Calloc(1,gearman_job_handle_t);
      gm_fun = (high == -1)? gearman_client_do_background : (high)? gearman_client_do_high_background : gearman_client_do_low_background ;
      client->lastretcode = gm_fun(client->client,fun,uval,work,strlen(work),job);
      ret = PROTECT(allocVector(STRSXP,1));
      SET_STRING_ELT(ret,0,mkChar(job));
      R_Free(job);
      UNPROTECT(1);
   } else {
      void *(*gm_fun)(gearman_client_st *client, const char *function_name, const char *unique, const void *workload, size_t workload_size, size_t *result_size, gearman_return_t *ret_ptr); 
      size_t resultsize;
      void *result;
      gm_fun = (high == -1)? gearman_client_do : (high)? gearman_client_do_high : gearman_client_do_low ;
      result = gm_fun(client->client,fun,uval,work,strlen(work),&resultsize,&client->lastretcode);
      ret = PROTECT(allocVector(STRSXP,1));
      SET_STRING_ELT(ret,0,mkCharLen((char *)result,resultsize));
      UNPROTECT(1);
   }

   return ret;
}
Beispiel #5
0
qboolean RE_RegisterModels_LevelLoadEnd(qboolean bDeleteEverythingNotUsedThisLevel /* = qfalse */)
{
	qboolean bAtLeastoneModelFreed = qfalse;

	if (gbInsideRegisterModel)
	{
		Com_DPrintf( "(Inside RE_RegisterModel (z_malloc recovery?), exiting...\n");
	}
	else
	{
		int iLoadedModelBytes	=	GetModelDataAllocSize();
		const int iMaxModelBytes=	r_modelpoolmegs->integer * 1024 * 1024;

		for (CachedModels_t::iterator itModel = CachedModels->begin(); itModel != CachedModels->end() && ( bDeleteEverythingNotUsedThisLevel || iLoadedModelBytes > iMaxModelBytes ); )
		{
			CachedEndianedModelBinary_t &CachedModel = (*itModel).second;

			qboolean bDeleteThis = qfalse;

			if (bDeleteEverythingNotUsedThisLevel)
			{
				bDeleteThis = (qboolean)(CachedModel.iLastLevelUsedOn != RE_RegisterMedia_GetLevel());
			}
			else
			{
				bDeleteThis = (qboolean)(CachedModel.iLastLevelUsedOn < RE_RegisterMedia_GetLevel());
			}

			// if it wasn't used on this level, dump it...
			//
			if (bDeleteThis)
			{
	#ifdef _DEBUG
//				LPCSTR psModelName = (*itModel).first.c_str();
//				ri.Printf( PRINT_DEVELOPER, "Dumping \"%s\"", psModelName);
//				ri.Printf( PRINT_DEVELOPER, ", used on lvl %d\n",CachedModel.iLastLevelUsedOn);
	#endif

				if (CachedModel.pModelDiskImage) {
					R_Free(CachedModel.pModelDiskImage);
					//CachedModel.pModelDiskImage = NULL;	// REM for reference, erase() call below negates the need for it.
					bAtLeastoneModelFreed = qtrue;
				}
				CachedModels->erase(itModel++);

				iLoadedModelBytes = GetModelDataAllocSize();
			}
			else
			{
				++itModel;
			}
		}
	}

	//ri.Printf( PRINT_DEVELOPER, "RE_RegisterModels_LevelLoadEnd(): Ok\n");

	return bAtLeastoneModelFreed;
}
Beispiel #6
0
// only called from devmapbsp, devmapall, or ...
//
void RE_AnimationCFGs_DeleteAll(void)
{
	for (AnimationCFGs_t::iterator it = AnimationCFGs.begin(); it != AnimationCFGs.end(); ++it)
	{
		char *psText = (*it).second;
		R_Free(psText);
	}

	AnimationCFGs.clear();
}
Beispiel #7
0
/*
* R_VBOElemBuffer
*/
static elem_t *R_VBOElemBuffer( unsigned numElems )
{
	if( numElems > r_vbo_numtempelems ) {
		if( r_vbo_numtempelems )
			R_Free( r_vbo_tempelems );
		r_vbo_numtempelems = numElems;
		r_vbo_tempelems = ( elem_t * )R_Malloc( sizeof( *r_vbo_tempelems ) * numElems );
	}

	return r_vbo_tempelems;
}
Beispiel #8
0
/*
* R_VBOVertBuffer
*/
static void *R_VBOVertBuffer( unsigned numVerts, size_t vertSize )
{
	size_t size = numVerts * vertSize;
	if( size > r_vbo_tempvsoupsize ) {
		if( r_vbo_tempvsoup )
			R_Free( r_vbo_tempvsoup );
		r_vbo_tempvsoupsize = size;
		r_vbo_tempvsoup = ( float * )R_Malloc( size );
	}
	return r_vbo_tempvsoup;
}
Beispiel #9
0
SEXP finalizeclient(SEXP Sclient){
   rgearman_client_t *client = (rgearman_client_t *)R_ExternalPtrAddr(Sclient);

   if (client){
      gearman_client_free(client->client);
      R_Free(client);
   } else
      warning("GearmanClient::finalize called with NULL client");

   return R_NilValue;
}
Beispiel #10
0
/*
* R_ShutdownCinematics
*/
void R_ShutdownCinematics( void ) {
	r_cinhandle_t *handle, *hnode, *next;

	hnode = &r_cinematics_headnode;
	for( handle = hnode->prev; handle != hnode; handle = next ) {
		next = handle->prev;
		R_FreeCinematic( handle->id );
	}

	R_Free( r_cinematics );
}
Beispiel #11
0
// Compute Euclidean (L2)/Manhattan (L1) distance map of matrix _a 
// Input: numeric matrix _a, of size width*height, where 0 is background and everything else is foreground. _a shouldn't contain any NAs
// Input: integer _metric. If 0, will compute Euclidean distance and Manhattan distance otherwise
// Output: distance matrix of same size as _a
SEXP distmap(SEXP _a, SEXP _metric) {
  SEXP res;
  int i,nprotect=0,nz;
  
  // check validity
  validImage(_a,0);
  
  // initialize width, height, dim
  width=INTEGER(GET_DIM(_a))[0];
  height=INTEGER(GET_DIM(_a))[1];
  nz=getNumberOfFrames(_a,0);
  
  // initialize vj, where (i,vj[i]) are the coordinates of the closest background pixel to a(i,j) with vj[i]>=j
  vj=(int *)R_Calloc(height,int);
  
  // initialize d, the output distance matrix
  PROTECT(res = allocVector(REALSXP, XLENGTH(_a)) );
  nprotect++;
  DUPLICATE_ATTRIB(res, _a);
  
  d=REAL(res);
  for (i=0;i<height*width*nz;i++) d[i]=R_PosInf;
  
  // initialize dist, the distance type
  metric=INTEGER(_metric)[0];
  
  // do the job
  int sizexy = height*width;
  int offset = 0;
  
  for (i=0; i<nz; i++, offset+=sizexy) {
    d = &(REAL(res)[offset]);
    
    switch (TYPEOF(_a)) {
    case LGLSXP:
    case INTSXP:
      _distmap<int>( &(INTEGER(_a)[offset]) );
      break;
    case REALSXP:
      _distmap<double>( &(REAL(_a)[offset]) );
      break;
    }
  }
  
  // final square root for Euclidean distance
  d=REAL(res);
  if (metric==0) for (i=0;i<height*width*nz;i++) d[i]=sqrt(d[i]);
  
  R_Free(vj);
  
  UNPROTECT (nprotect);
  return res;
}
Beispiel #12
0
void RE_SaveJPG(const char * filename, int quality, int image_width, int image_height, byte *image_buffer, int padding)
{
	byte *out;
	size_t bufSize;

	bufSize = image_width * image_height * 3;
	out = (byte *) R_Malloc( bufSize, TAG_TEMP_WORKSPACE, qfalse );

	bufSize = RE_SaveJPGToBuffer(out, bufSize, quality, image_width, image_height, image_buffer, padding, false);
	ri.FS_WriteFile(filename, out, bufSize);

	R_Free(out);
}
Beispiel #13
0
/*
* R_FreeCinematic
*/
void R_FreeCinematic( unsigned int id ) {
	qmutex_t *lock;
	r_cinhandle_t *handle;

	handle = R_GetCinematicHandleById( id );
	if( !handle ) {
		return;
	}

	lock = handle->lock;
	ri.Mutex_Lock( lock );

	ri.CIN_Close( handle->cin );
	handle->cin = NULL;
	handle->lock = NULL;

	assert( handle->name );
	R_Free( handle->name );
	handle->name = NULL;

	assert( handle->uploadName );
	R_Free( handle->uploadName );
	handle->uploadName = NULL;

	// remove from linked active list
	handle->prev->next = handle->next;
	handle->next->prev = handle->prev;

	// insert into linked free list
	handle->next = r_free_cinematics;
	r_free_cinematics = handle;

	ri.Mutex_Unlock( lock );

	ri.Mutex_Destroy( &lock );
}
Beispiel #14
0
/*
================
R_MipMap2

Uses temp mem, but then copies back to input, quartering the size of the texture
Proper linear filter
================
*/
static void R_MipMap2( unsigned *in, int inWidth, int inHeight ) {
	int			i, j, k;
	byte		*outpix;
	int			inWidthMask, inHeightMask;
	int			total;
	int			outWidth, outHeight;
	unsigned	*temp;

	outWidth = inWidth >> 1;
	outHeight = inHeight >> 1;
	temp = (unsigned int *) R_Malloc( outWidth * outHeight * 4, TAG_TEMP_WORKSPACE, qfalse );

	inWidthMask = inWidth - 1;
	inHeightMask = inHeight - 1;

	for ( i = 0 ; i < outHeight ; i++ ) {
		for ( j = 0 ; j < outWidth ; j++ ) {
			outpix = (byte *) ( temp + i * outWidth + j );
			for ( k = 0 ; k < 4 ; k++ ) {
				total =
					1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
					2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
					2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
					1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +

					2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
					4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
					4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
					2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +

					2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
					4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
					4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
					2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +

					1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
					2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
					2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
					1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k];
				outpix[k] = total / 36;
			}
		}
	}

	memcpy( in, temp, outWidth * outHeight * 4 );
	R_Free( temp );
}
Beispiel #15
0
// Compute Euclidean (L2)/Manhattan (L1) distance map of matrix _a 
// Input: numeric matrix _a, of size width*height, where 0 is background and everything else is foreground. _a shouldn't contain any NAs
// Input: integer _metric. If 0, will compute Euclidean distance and Manhattan distance otherwise
// Output: distance matrix of same size as _a
SEXP distmap(SEXP _a, SEXP _metric) {
  SEXP res;
  int i,nprotect=0,nz;

  // check validity
  validImage(_a,0);

  // initialize width, height, dim
  width=INTEGER(GET_DIM(_a))[0];
  height=INTEGER(GET_DIM(_a))[1];
  nz=getNumberOfFrames(_a,0);

 // initialize vj, where (i,vj[i]) are the coordinates of the closest background pixel to a(i,j) with vj[i]>=j
  vj=(int *)R_Calloc(height,int);

  // initialize a
  a=REAL(_a);

  // initialize d, the output distance matrix
  PROTECT(res=Rf_duplicate(_a));
  nprotect++;
  d=REAL(res);
  for (i=0;i<height*width*nz;i++) d[i]=R_PosInf;
  
  // initialize dist, the distance type
  metric=INTEGER(_metric)[0];
   
  // do the job
  for (i=0;i<nz;i++) {
    distmap_onesided(1);
    distmap_onesided(0);
    a=a+height*width;
    d=d+height*width;
  }

  // final square root for Euclidean distance
  d=REAL(res);
  if (metric==0) for (i=0;i<height*width*nz;i++) d[i]=sqrt(d[i]);

  // free vj
  R_Free(vj);

  UNPROTECT (nprotect);
  return res;
}
Beispiel #16
0
/*
* R_ReserveDrawSurfaces
*/
static void R_ReserveDrawSurfaces( drawList_t *list, int minMeshes )
{
	int oldSize, newSize;
	sortedDrawSurf_t *newDs;
	sortedDrawSurf_t *ds = list->drawSurfs;
	int maxMeshes = list->maxDrawSurfs;

	oldSize = maxMeshes;
	newSize = max( minMeshes, oldSize * 2 );

	newDs = R_Malloc( newSize * sizeof( sortedDrawSurf_t ) );
	if( ds ) {
		memcpy( newDs, ds, oldSize * sizeof( sortedDrawSurf_t ) );
		R_Free( ds );
	}
	
	list->drawSurfs = newDs;
	list->maxDrawSurfs = newSize;
}
Beispiel #17
0
static void RE_RegisterModels_DeleteAll(void)
{
	if(!CachedModels) {
		return;	//argh!
	}

	for (CachedModels_t::iterator itModel = CachedModels->begin(); itModel != CachedModels->end(); )
	{
		CachedEndianedModelBinary_t &CachedModel = (*itModel).second;

		if (CachedModel.pModelDiskImage) {
			R_Free(CachedModel.pModelDiskImage);
		}

		CachedModels->erase(itModel++);
	}

	extern void RE_AnimationCFGs_DeleteAll(void);
	RE_AnimationCFGs_DeleteAll();
}
Beispiel #18
0
/*
* R_ShutdownVBO
*/
void R_ShutdownVBO( void )
{
	mesh_vbo_t *vbo;
	vbohandle_t *vboh, *next, *hnode;

	if( !r_num_active_vbos ) {
		return;
	}

	hnode = &r_vbohandles_headnode;
	for( vboh = hnode->prev; vboh != hnode; vboh = next ) {
		next = vboh->prev;
		vbo = &r_mesh_vbo[vboh->index];

		R_ReleaseMeshVBO( vbo );
	}

	if( r_vbo_tempelems ) {
		R_Free( r_vbo_tempelems );
	}
	r_vbo_numtempelems = 0;
}
Beispiel #19
0
void do_free(SEXP x)
{
  void* addr = R_ExternalPtrAddr(x);
  R_Free(addr);
}
Beispiel #20
0
SEXP clahe (SEXP x, SEXP _uiNrX, SEXP _uiNrY, SEXP _uiNrBins, SEXP _fCliplimit, SEXP _keepRange) {
  int nx, ny, nz, i, j;
  unsigned int uiNrX, uiNrY, uiNrBins;
  float fCliplimit;
  int keepRange;
  double *src, *tgt;
  SEXP res;
  
  kz_pixel_t min = 0, max = uiNR_OF_GREY-1;
  kz_pixel_t *img;
  
  double maxPixelValue = uiNR_OF_GREY-1;
  
  PROTECT( res = allocVector(REALSXP, XLENGTH(x)) );
  DUPLICATE_ATTRIB(res, x);
  
  nx = INTEGER(GET_DIM(x))[0];
  ny = INTEGER(GET_DIM(x))[1];
  nz = getNumberOfFrames(x, 0);
  
  uiNrX = INTEGER(_uiNrX)[0];
  uiNrY = INTEGER(_uiNrY)[0];
  uiNrBins = INTEGER(_uiNrBins)[0];
  fCliplimit = REAL(_fCliplimit)[0];
  keepRange = LOGICAL(_keepRange)[0];
  
  img = R_Calloc(nx*ny, kz_pixel_t);
  
  // process channels separately
  for(j = 0; j < nz; j++) {
    src = &(REAL(x)[j*nx*ny]);
    tgt = &(REAL(res)[j*nx*ny]);
    
    if (keepRange) {
      min = uiNR_OF_GREY-1;
      max = 0;
    }
    
    // convert frame to CLAHE-compatible format
    for (i = 0; i < nx*ny; i++) {
      double el = src[i];
      
      // clip
      if (el < 0.0) el = 0;
      else if (el > 1.0) el = 1.0;
      // convert to int
      kz_pixel_t nel = (kz_pixel_t) round(el * maxPixelValue);
      
      if (keepRange) {
        if (nel < min) min = nel;
        if (nel > max) max = nel;
      }
      
      img[i] = nel;
    }
    
    int val = CLAHE (img, (unsigned int) nx, (unsigned int) ny,
                     min, max, uiNrX, uiNrY, uiNrBins, fCliplimit);
    
    // translate internal error codes
    switch (val) {
    case -1:
      error("# of regions x-direction too large");
      break;
    case -2:
      error("# of regions y-direction too large");
      break;
    case -3:
      error("x-resolution no multiple of 'nx'");
      break;
    case -4:
      error("y-resolution no multiple of 'ny'");
      break;
    case -5:
      error("maximum too large");
      break;
    case -6:
      error("minimum equal or larger than maximum");
      break;
    case -7:
      error("at least 4 contextual regions required");
      break;
    case -8:
      error("not enough memory! (try reducing 'bins')");
      break;
    }
    
    // convert back to [0:1] range
    for (i = 0; i < nx*ny; i++) {
      tgt[i] = (double) img[i] / maxPixelValue;
    }
  }
  
  R_Free(img);
  
  UNPROTECT(1);
  
  return res;
}
Beispiel #21
0
/*
* Mod_LoadSkeletalModel
*/
void Mod_LoadSkeletalModel( model_t *mod, const model_t *parent, void *buffer, bspFormatDesc_t *unused )
{
	unsigned int i, j, k;
	size_t filesize;
	qbyte *pbase;
	size_t memsize;
	qbyte *pmem;
	iqmheader_t *header;
	char *texts;
	iqmvertexarray_t *va;
	iqmjoint_t *joints;
	bonepose_t *baseposes;
	iqmpose_t *poses;
	unsigned short *framedata;
	const int *inelems;
	elem_t *outelems;
	iqmmesh_t *inmesh;
	iqmbounds_t *inbounds;
	float *vposition, *vtexcoord, *vnormal, *vtangent;
	qbyte *vblendindices_byte, *vblendweights_byte;
	int *vblendindexes_int;
	float *vblendweights_float;
	mskmodel_t *poutmodel;

	baseposes = NULL;
	header = ( iqmheader_t * )buffer;

	// check IQM magic
	if( memcmp( header->magic, "INTERQUAKEMODEL", 16 ) ) {
		ri.Com_Printf( S_COLOR_RED "ERROR: %s is not an Inter-Quake Model\n", mod->name );
		goto error;
	}

	// check header version
	header->version = LittleLong( header->version );
	if( header->version != IQM_VERSION ) {
		ri.Com_Printf( S_COLOR_RED "ERROR: %s has wrong type number (%i should be %i)\n", mod->name, header->version, IQM_VERSION );
		goto error;
	}

	// byteswap header
#define H_SWAP(s) (header->s = LittleLong( header->s ))
	H_SWAP( filesize );
	H_SWAP( flags );
	H_SWAP( num_text );
	H_SWAP( ofs_text );
	H_SWAP( num_meshes );
	H_SWAP( ofs_meshes );
	H_SWAP( num_vertexarrays );
	H_SWAP( num_vertexes );
	H_SWAP( ofs_vertexarrays );
	H_SWAP( num_triangles );
	H_SWAP( ofs_triangles );
	H_SWAP( ofs_adjacency );
	H_SWAP( num_joints );
	H_SWAP( ofs_joints );
	H_SWAP( num_poses );
	H_SWAP( ofs_poses );
	H_SWAP( num_anims );
	H_SWAP( ofs_anims );
	H_SWAP( num_frames );
	H_SWAP( num_framechannels );
	H_SWAP( ofs_frames );
	H_SWAP( ofs_bounds );
	H_SWAP( num_comment );
	H_SWAP( ofs_comment );
	H_SWAP( num_extensions );
	H_SWAP( ofs_extensions );
#undef H_SWAP

	if( header->num_triangles < 1 || header->num_vertexes < 3 || header->num_vertexarrays < 1 || header->num_meshes < 1 ) {
		ri.Com_Printf( S_COLOR_RED "ERROR: %s has no geometry\n", mod->name );
		goto error;
	}
	if( header->num_frames < 1 || header->num_anims < 1 ) {
		ri.Com_Printf( S_COLOR_RED "ERROR: %s has no animations\n", mod->name );
		goto error;
	}
	if( header->num_joints != header->num_poses ) {
		ri.Com_Printf( S_COLOR_RED "ERROR: %s has an invalid number of poses: %i vs %i\n", mod->name, header->num_joints, header->num_poses );
		goto error;
	}
	if( !header->ofs_bounds ) {
		ri.Com_Printf( S_COLOR_RED "ERROR: %s has no frame bounds\n", mod->name );
		goto error;
	}

	pbase = ( qbyte * )buffer;
	filesize = header->filesize;

	// check data offsets against the filesize
	if( header->ofs_text + header->num_text > filesize
		|| header->ofs_vertexarrays + header->num_vertexarrays * sizeof( iqmvertexarray_t ) > filesize
		|| header->ofs_joints + header->num_joints * sizeof( iqmjoint_t ) > filesize
		|| header->ofs_frames + header->num_frames * header->num_framechannels * sizeof( unsigned short ) > filesize
		|| header->ofs_triangles + header->num_triangles * sizeof( int[3] ) > filesize
		|| header->ofs_meshes + header->num_meshes * sizeof( iqmmesh_t ) > filesize
		|| header->ofs_bounds + header->num_frames * sizeof( iqmbounds_t ) > filesize
		) {
		ri.Com_Printf( S_COLOR_RED "ERROR: %s has invalid size or offset information\n", mod->name );
		goto error;
	}

	poutmodel = mod->extradata = Mod_Malloc( mod, sizeof( *poutmodel ) );


	// load text
	texts = Mod_Malloc( mod, header->num_text + 1 );
	if( header->ofs_text ) {
		memcpy( texts, (const char *)(pbase + header->ofs_text), header->num_text );
	}
	texts[header->ofs_text] = '\0';


	// load vertex arrays
	vposition = NULL;
	vtexcoord = NULL;
	vnormal = NULL;
	vtangent = NULL;
	vblendindices_byte = NULL;
	vblendindexes_int = NULL;
	vblendweights_byte = NULL;
	vblendweights_float = NULL;

	va = ( iqmvertexarray_t * )( pbase + header->ofs_vertexarrays );
	for( i = 0; i < header->num_vertexarrays; i++ ) {
		size_t vsize;

		va[i].type = LittleLong( va[i].type );
		va[i].flags = LittleLong( va[i].flags );
		va[i].format = LittleLong( va[i].format );
		va[i].size = LittleLong( va[i].size );
		va[i].offset = LittleLong( va[i].offset );

		vsize = header->num_vertexes*va[i].size;
		switch( va[i].format ) { 
			case IQM_FLOAT:
				vsize *= sizeof( float );
				break;
			case IQM_INT:
			case IQM_UINT:
				vsize *= sizeof( int );
				break;
			case IQM_BYTE:
			case IQM_UBYTE:
				vsize *= sizeof( unsigned char );
				break;
			default:
				continue;
		}

		if( va[i].offset + vsize > filesize ) {
			continue;
		}

		switch( va[i].type ) {
			case IQM_POSITION:
				if( va[i].format == IQM_FLOAT && va[i].size == 3 ) {
					vposition = ( float * )( pbase + va[i].offset );
				}
				break;
			case IQM_TEXCOORD:
				if( va[i].format == IQM_FLOAT && va[i].size == 2 ) {
					vtexcoord = ( float * )( pbase + va[i].offset );
				}
				break;
			case IQM_NORMAL:
				if( va[i].format == IQM_FLOAT && va[i].size == 3 ) {
					vnormal = ( float * )( pbase + va[i].offset );
				}
				break;
			case IQM_TANGENT:
				if( va[i].format == IQM_FLOAT && va[i].size == 4 ) {
					vtangent = ( float * )( pbase + va[i].offset );
				}
				break;
			case IQM_BLENDINDEXES:
				if( va[i].size != SKM_MAX_WEIGHTS )
					break;
				if( va[i].format == IQM_BYTE || va[i].format == IQM_UBYTE ) {
					vblendindices_byte = ( qbyte * )( pbase + va[i].offset );
				}
				else if( va[i].format == IQM_INT || va[i].format == IQM_UINT ) {
					vblendindexes_int = ( int * )( pbase + va[i].offset );
				}
				break;
			case IQM_BLENDWEIGHTS:
				if( va[i].size != SKM_MAX_WEIGHTS )
					break;
				if( va[i].format == IQM_UBYTE ) {
					vblendweights_byte = ( qbyte * )( pbase + va[i].offset );
				}
				else if( va[i].format == IQM_FLOAT ) {
					vblendweights_float = ( float * )( pbase + va[i].offset );
				}
				break;
			default:
				break;
		}
	}

	if( !vposition || !vtexcoord 
		|| !(vblendindices_byte || vblendindexes_int) 
		|| !(vblendweights_byte || vblendweights_float) ) {
		ri.Com_Printf( S_COLOR_RED "ERROR: %s is missing vertex array data\n", mod->name );
		goto error;
	}

	// load joints
	memsize = 0;
	memsize += sizeof( bonepose_t ) * header->num_joints;
	pmem = Mod_Malloc( mod, memsize );

	baseposes = ( void * )pmem; pmem += sizeof( *baseposes );

	memsize = 0;
	memsize += sizeof( mskbone_t ) * header->num_joints;
	memsize += sizeof( bonepose_t ) * header->num_joints;
	pmem = Mod_Malloc( mod, memsize );

	poutmodel->numbones = header->num_joints;
	poutmodel->bones = ( void * )pmem; pmem += sizeof( *poutmodel->bones ) * poutmodel->numbones;
	poutmodel->invbaseposes = ( void * )pmem; pmem += sizeof( *poutmodel->invbaseposes ) * poutmodel->numbones;

	joints = ( iqmjoint_t * )( pbase + header->ofs_joints );
	for( i = 0; i < poutmodel->numbones; i++ ) {
		joints[i].name = LittleLong( joints[i].name );
		joints[i].parent = LittleLong( joints[i].parent );

		for( j = 0; j < 3; j++ ) {
			joints[i].translate[j] = LittleFloat( joints[i].translate[j] );
			joints[i].rotate[j] = LittleFloat( joints[i].rotate[j] );
			joints[i].scale[j] = LittleFloat( joints[i].scale[j] );
		}

		if( joints[i].parent >= (int)i ) {
			ri.Com_Printf( S_COLOR_RED "ERROR: %s bone[%i].parent(%i) >= %i\n", mod->name, i, joints[i].parent, i );
			goto error;
		}

		poutmodel->bones[i].name = texts + joints[i].name;
		poutmodel->bones[i].parent = joints[i].parent;

		DualQuat_FromQuat3AndVector( joints[i].rotate, joints[i].translate, baseposes[i].dualquat );

		// scale is unused

		// reconstruct invserse bone pose

		if( joints[i].parent >= 0 )
		{
			bonepose_t bp, *pbp;
			bp = baseposes[i];
			pbp = &baseposes[joints[i].parent];

			DualQuat_Multiply( pbp->dualquat, bp.dualquat, baseposes[i].dualquat );
		}

		DualQuat_Copy( baseposes[i].dualquat, poutmodel->invbaseposes[i].dualquat );
		DualQuat_Invert( poutmodel->invbaseposes[i].dualquat );
	}


	// load frames
	poses = ( iqmpose_t * )( pbase + header->ofs_poses );
	for( i = 0; i < header->num_poses; i++ ) {
		poses[i].parent = LittleLong( poses[i].parent );
		poses[i].mask = LittleLong( poses[i].mask );

		for( j = 0; j < 10; j++ ) {
			poses[i].channeloffset[j] = LittleFloat( poses[i].channeloffset[j] );
			poses[i].channelscale[j] = LittleFloat( poses[i].channelscale[j] );
		}
	}

	memsize = 0;
	memsize += sizeof( mskframe_t ) * header->num_frames;
	memsize += sizeof( bonepose_t ) * header->num_joints * header->num_frames;
	pmem = Mod_Malloc( mod, memsize );

	poutmodel->numframes = header->num_frames;
	poutmodel->frames = ( mskframe_t * )pmem; pmem += sizeof( mskframe_t ) * poutmodel->numframes;

	framedata = ( unsigned short * )( pbase + header->ofs_frames );
	for( i = 0; i < header->num_frames; i++ ) {
		bonepose_t *pbp;
		vec3_t translate;
		quat_t rotate;

		poutmodel->frames[i].boneposes = ( bonepose_t * )pmem; pmem += sizeof( bonepose_t ) * poutmodel->numbones;

		for( j = 0, pbp = poutmodel->frames[i].boneposes; j < header->num_poses; j++, pbp++ ) {
			translate[0] = poses[j].channeloffset[0]; if( poses[j].mask & 0x01 ) translate[0] += *framedata++ * poses[j].channelscale[0];
			translate[1] = poses[j].channeloffset[1]; if( poses[j].mask & 0x02 ) translate[1] += *framedata++ * poses[j].channelscale[1];
			translate[2] = poses[j].channeloffset[2]; if( poses[j].mask & 0x04 ) translate[2] += *framedata++ * poses[j].channelscale[2];

			rotate[0] = poses[j].channeloffset[3]; if( poses[j].mask & 0x08 ) rotate[0] += *framedata++ * poses[j].channelscale[3];
			rotate[1] = poses[j].channeloffset[4]; if( poses[j].mask & 0x10 ) rotate[1] += *framedata++ * poses[j].channelscale[4];
			rotate[2] = poses[j].channeloffset[5]; if( poses[j].mask & 0x20 ) rotate[2] += *framedata++ * poses[j].channelscale[5];
			rotate[3] = poses[j].channeloffset[6]; if( poses[j].mask & 0x40 ) rotate[3] += *framedata++ * poses[j].channelscale[6];
			if( rotate[3] > 0 ) {
				Vector4Inverse( rotate );
			}
			Vector4Normalize( rotate );

			// scale is unused
			if( poses[j].mask & 0x80  ) framedata++;
			if( poses[j].mask & 0x100 ) framedata++;
			if( poses[j].mask & 0x200 ) framedata++;

			DualQuat_FromQuatAndVector( rotate, translate, pbp->dualquat );
		}
	}


	// load triangles
	memsize = 0;
	memsize += sizeof( *outelems ) * header->num_triangles * 3;
	pmem = Mod_Malloc( mod, memsize );

	poutmodel->numtris = header->num_triangles;
	poutmodel->elems = ( elem_t * )pmem; pmem += sizeof( *outelems ) * header->num_triangles * 3;

	inelems = ( const int * )(pbase + header->ofs_triangles);
	outelems = poutmodel->elems;

	for( i = 0; i < header->num_triangles; i++ ) {
		for( j = 0; j < 3; j++ ) {
			outelems[j] = LittleLong( inelems[j] );
		}
		inelems += 3;
		outelems += 3;
	}


	// load vertices
	memsize = 0;
	memsize += sizeof( *poutmodel->sVectorsArray ) * header->num_vertexes;	// 16-bytes aligned
	memsize += sizeof( *poutmodel->xyzArray ) * header->num_vertexes;
	memsize += sizeof( *poutmodel->normalsArray ) * header->num_vertexes;
	memsize += sizeof( *poutmodel->stArray ) * header->num_vertexes;
	memsize += sizeof( *poutmodel->blendWeights ) * header->num_vertexes * SKM_MAX_WEIGHTS;
	memsize += sizeof( *poutmodel->blendIndices ) * header->num_vertexes * SKM_MAX_WEIGHTS;
	pmem = Mod_Malloc( mod, memsize );

	poutmodel->numverts = header->num_vertexes;

	// S-vectors
	poutmodel->sVectorsArray = ( vec4_t * )pmem; pmem += sizeof( *poutmodel->sVectorsArray ) * header->num_vertexes;

	if( vtangent ) {
		for( i = 0; i < header->num_vertexes; i++ ) {
			for( j = 0; j < 4; j++ ) {
				poutmodel->sVectorsArray[i][j] = LittleFloat( vtangent[j] );
			}
			vtangent += 4;
		}
	}

	// XYZ positions
	poutmodel->xyzArray = ( vec4_t * )pmem; pmem += sizeof( *poutmodel->xyzArray ) * header->num_vertexes;
	for( i = 0; i < header->num_vertexes; i++ ) {
		for( j = 0; j < 3; j++ ) {
			poutmodel->xyzArray[i][j] = LittleFloat( vposition[j] );
		}
		poutmodel->xyzArray[i][3] = 1;
		vposition += 3;
	}

	// normals
	poutmodel->normalsArray = ( vec4_t * )pmem; pmem += sizeof( *poutmodel->normalsArray ) * header->num_vertexes;
	for( i = 0; i < header->num_vertexes; i++ ) {
		for( j = 0; j < 3; j++ ) {
			poutmodel->normalsArray[i][j] = LittleFloat( vnormal[j] );
		}
		poutmodel->normalsArray[i][3] = 0;
		vnormal += 3;
	}

	// texture coordinates
	poutmodel->stArray = ( vec2_t * )pmem; pmem += sizeof( *poutmodel->stArray ) * header->num_vertexes;
	for( i = 0; i < header->num_vertexes; i++ ) {
		for( j = 0; j < 2; j++ ) {
			poutmodel->stArray[i][j] = LittleFloat( vtexcoord[j] );
		}
		vtexcoord += 2;
	}

	if( !vtangent ) {
		// if the loaded file is missing precomputed S-vectors, compute them now
		R_BuildTangentVectors( poutmodel->numverts, poutmodel->xyzArray, poutmodel->normalsArray, poutmodel->stArray, 
			poutmodel->numtris, poutmodel->elems, poutmodel->sVectorsArray );
	}

	// blend indices
	poutmodel->blendIndices = ( qbyte * )pmem; pmem += sizeof( *poutmodel->blendIndices ) * header->num_vertexes * SKM_MAX_WEIGHTS;
	if( vblendindices_byte ) {
		memcpy( poutmodel->blendIndices, vblendindices_byte, sizeof( qbyte ) * header->num_vertexes * SKM_MAX_WEIGHTS );
	} else if( vblendindexes_int ) {
		for( j = 0; j < header->num_vertexes * SKM_MAX_WEIGHTS; j++ ) {
			poutmodel->blendIndices[j] = LittleLong( vblendindexes_int[j] );
		}
	}

	// blend weights
	poutmodel->blendWeights = ( qbyte * )pmem; pmem += sizeof( *poutmodel->blendWeights ) * header->num_vertexes * SKM_MAX_WEIGHTS;
	if( vblendweights_byte ) {
		memcpy( poutmodel->blendWeights, vblendweights_byte, sizeof( qbyte ) * header->num_vertexes * SKM_MAX_WEIGHTS );
	}
	else if( vblendweights_float ) {
		for( j = 0; j < header->num_vertexes * SKM_MAX_WEIGHTS; j++ ) {
			poutmodel->blendWeights[j] = LittleFloat( vblendweights_float[j] ) * 255.0f;
		}
	}


	// blends
	memsize = 0;
	memsize += poutmodel->numverts * ( sizeof( mskblend_t ) + sizeof( unsigned int ) );
	pmem = Mod_Malloc( mod, memsize );

	poutmodel->numblends = 0;
	poutmodel->blends = ( mskblend_t * )pmem; pmem += sizeof( *poutmodel->blends ) * poutmodel->numverts;
	poutmodel->vertexBlends = ( unsigned int * )pmem;

	vblendindices_byte = poutmodel->blendIndices;
	vblendweights_byte = poutmodel->blendWeights;

	for( i = 0; i < poutmodel->numverts; i++ ) {
		mskblend_t blend;

		for( j = 0; j < SKM_MAX_WEIGHTS; j++ ) {
			blend.indices[j] = vblendindices_byte[j];
			blend.weights[j] = vblendweights_byte[j];
		}

		poutmodel->vertexBlends[i] = Mod_SkeletalModel_AddBlend( poutmodel, &blend );

		vblendindices_byte += SKM_MAX_WEIGHTS;
		vblendweights_byte += SKM_MAX_WEIGHTS;
	}

	// meshes
	memsize = 0;
	memsize += sizeof( mskmesh_t ) * header->num_meshes;
	memsize += sizeof( drawSurfaceSkeletal_t ) * header->num_meshes;
	pmem = Mod_Malloc( mod, memsize );

	poutmodel->nummeshes = header->num_meshes;
	poutmodel->meshes = ( mskmesh_t * )pmem; pmem += sizeof( *poutmodel->meshes ) * header->num_meshes;

	inmesh = ( iqmmesh_t * )(pbase + header->ofs_meshes);
	for( i = 0; i < header->num_meshes; i++ ) {
		inmesh[i].name = LittleLong( inmesh[i].name );
		inmesh[i].material = LittleLong( inmesh[i].material );
		inmesh[i].first_vertex = LittleLong( inmesh[i].first_vertex );
		inmesh[i].num_vertexes = LittleLong( inmesh[i].num_vertexes );
		inmesh[i].first_triangle = LittleLong( inmesh[i].first_triangle );
		inmesh[i].num_triangles = LittleLong( inmesh[i].num_triangles );

		poutmodel->meshes[i].name = texts + inmesh[i].name;
		Mod_StripLODSuffix( poutmodel->meshes[i].name );

		poutmodel->meshes[i].skin.name = texts + inmesh[i].material;
		poutmodel->meshes[i].skin.shader = R_RegisterSkin( poutmodel->meshes[i].skin.name );

		poutmodel->meshes[i].elems = poutmodel->elems + inmesh[i].first_triangle * 3;
		poutmodel->meshes[i].numtris = inmesh[i].num_triangles;

		poutmodel->meshes[i].numverts = inmesh[i].num_vertexes;
		poutmodel->meshes[i].xyzArray = poutmodel->xyzArray + inmesh[i].first_vertex;
		poutmodel->meshes[i].normalsArray = poutmodel->normalsArray + inmesh[i].first_vertex;
		poutmodel->meshes[i].stArray = poutmodel->stArray + inmesh[i].first_vertex;
		poutmodel->meshes[i].sVectorsArray = poutmodel->sVectorsArray + inmesh[i].first_vertex;

		poutmodel->meshes[i].blendIndices = poutmodel->blendIndices + inmesh[i].first_vertex * SKM_MAX_WEIGHTS;
		poutmodel->meshes[i].blendWeights = poutmodel->blendWeights + inmesh[i].first_vertex * SKM_MAX_WEIGHTS;

		poutmodel->meshes[i].vertexBlends = poutmodel->vertexBlends + inmesh[i].first_vertex;

		// elements are always offset to start vertex 0 for each mesh
		outelems = poutmodel->meshes[i].elems;
		for( j = 0; j < poutmodel->meshes[i].numtris; j++ ) {
			outelems[0] -= inmesh[i].first_vertex;
			outelems[1] -= inmesh[i].first_vertex;
			outelems[2] -= inmesh[i].first_vertex;
			outelems += 3;
		}

		poutmodel->meshes[i].maxWeights = 1;

		vblendweights_byte = poutmodel->meshes[i].blendWeights;
		for( j = 0; j < poutmodel->meshes[i].numverts; j++ ) {
			for( k = 1; k < SKM_MAX_WEIGHTS && vblendweights_byte[k]; k++ );

			if( k > poutmodel->meshes[i].maxWeights ) {
				poutmodel->meshes[i].maxWeights = k;
				if( k == SKM_MAX_WEIGHTS ) {
					break;
				}
			}
			vblendweights_byte += SKM_MAX_WEIGHTS;
		}

		// creating a VBO only makes sense if GLSL is present and the number of bones 
		// we can handle on the GPU is sufficient
		if( glConfig.ext.vertex_buffer_object && poutmodel->numbones <= glConfig.maxGLSLBones ) {
			// build a static vertex buffer object for this mesh
			Mod_SkeletalBuildStaticVBOForMesh( &poutmodel->meshes[i] );
		}
	}

	poutmodel->drawSurfs = ( drawSurfaceSkeletal_t * )pmem; pmem += sizeof( *poutmodel->drawSurfs ) * header->num_meshes;
	for( i = 0; i < header->num_meshes; i++ ) {
		poutmodel->drawSurfs[i].type = ST_SKELETAL;
		poutmodel->drawSurfs[i].model = mod;
		poutmodel->drawSurfs[i].mesh = poutmodel->meshes + i;
	}

	// bounds
	ClearBounds( mod->mins, mod->maxs );

	inbounds = ( iqmbounds_t * )(pbase + header->ofs_bounds);
	for( i = 0; i < header->num_frames; i++ ) {
		for( j = 0; j < 3; j++ ) {
			inbounds[i].bbmin[j] = LittleFloat( inbounds[i].bbmin[j] );
			inbounds[i].bbmax[j] = LittleFloat( inbounds[i].bbmax[j] );
		}
		inbounds[i].radius = LittleFloat( inbounds[i].radius );
		inbounds[i].xyradius = LittleFloat( inbounds[i].xyradius );

		VectorCopy( inbounds[i].bbmin, poutmodel->frames[i].mins );
		VectorCopy( inbounds[i].bbmax, poutmodel->frames[i].maxs );
		poutmodel->frames[i].radius = inbounds[i].radius;

		AddPointToBounds( poutmodel->frames[i].mins, mod->mins, mod->maxs );
		AddPointToBounds( poutmodel->frames[i].maxs, mod->mins, mod->maxs );
	}

	mod->radius = RadiusFromBounds( mod->mins, mod->maxs );
	mod->type = mod_skeletal;
	mod->registrationSequence = rsh.registrationSequence;
	mod->touch = &Mod_TouchSkeletalModel;

	R_Free( baseposes );
	return;

error:
	if( baseposes ) {
		R_Free( baseposes );
	}
	mod->type = mod_bad;
}
Beispiel #22
0
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Bruvo's Distance implementing Addition, Loss, and Infinite models for
	imputation of missing data.

	NOTE: The input needs to be divided by the repeat length beforehand for this
	to work. 

	in: a matrix of two individuals
	out: a double value that will be the output from bruvo's distance.
	n: number of individuals(2)
	nall: number of alleles
	perm: a vector from the permn function in R
	woo: p * p!
	loss: TRUE/FALSE: impute under genome loss model.
	add: TRUE/FALSE: impute under genome addition model. 
==============================================================================*/
double bruvo_dist(int *in, int *nall, int *perm, int *woo, int *loss, int *add, int old_model)
{
	// R_CheckUserInterrupt();
	int i; 
	int j; 
	int counter = 0;    // counter used for building arrays
	int n = 2;          // number of individuals
	int p = *nall;      // number of alleles
	int w = *woo;       // number of permutations = p * p!
	int loss_indicator = *loss; // 1 if the genome loss model should be used
	int add_indicator = *add;   // 1 if the genome addition model should be used

	int* genos;    // array to store the genotypes
	genos = R_Calloc(2*p, int);

	int zerocatch[2]; 	// 2 element array to store the number of missing 
					  	// alleles in each genotype. 
	 
	int** zero_ind;     // array to store the indices of the missing data for
						// each genotype
	zero_ind = R_Calloc(2, int*);
	zero_ind[0] = R_Calloc(p, int);
	zero_ind[1] = R_Calloc(p, int);

	int zerodiff;      	// used to check the amount of missing data different 
				       	// between the two genotypes

	double minn = 100; 	// The minimum distance 

	// reconstruct the genotype table.
	zerocatch[0] = 0;
	zerocatch[1] = 0;
	for(i = 0; i < n; i++)
	{
		for(j = 0; j < p; j++)
		{
			// Catch missing data here.
			if (in[counter] == 0)
			{
				if (zerocatch[i] == p - 1)
				{
					goto finalsteps;
				}
				zerocatch[i] += 1;
				// Rprintf("[%d]", zerocatch[i] - 1);
				zero_ind[i][zerocatch[i] - 1] = j;
			}
			genos[i*p + j] = in[counter++];
			// Rprintf("%d\t", genos[i*p + j]);
		}
		// Rprintf("\n");
	}
	// Rprintf("\n");
	zerodiff = abs(zerocatch[0] - zerocatch[1]);
	/*==========================================================================
	* Removing superfluous zeroes from the data. This is in the case that both
	* of the genotypes contain one or more zeroes.
	*
	* smaller and larger refer to the size of the genotypes.
	==========================================================================*/
	if (zerocatch[0] > 0 && zerocatch[1] > 0)
	{
		int smaller = 0;
		int larger = 1;
		int reduction = 0; 
		int i;
		int j;
		int zero_counter;
		int *perm_array;
		int *new_geno;
		int *new_alleles;

		if (zerodiff == 0)
		{
			reduction = p - zerocatch[0];
		}
		else
		{
			if (zerocatch[0] < zerocatch[1])
			{
				smaller = 1;
				larger = 0;
			}
			reduction = p - (zerocatch[smaller] - zerodiff);
		}
	
		new_alleles = R_Calloc(reduction, int);
		for (i = 0; i < reduction; i++)
		{
			new_alleles[i] = i;
		}
		w = fact(reduction) * reduction;
		perm_array = R_Calloc(w, int);
		perm_count = 0;
		permute(new_alleles, 0, reduction - 1, perm_array);
		new_geno = R_Calloc(reduction*n, int);
		counter = 0;
		for (i=0; i < n; i++)
		{
			zero_counter = zerocatch[larger];
			for (j = 0; j < p; j++)
			{
				if (genos[i*p + j] == 0 && zero_counter > 0)
				{
					zero_counter--;
				}
				else
				{
					new_geno[counter++] = genos[i*p + j];
				}
			}
		}
	
		minn = bruvo_dist(new_geno, &reduction, perm_array, &w, 
								&loss_indicator, &add_indicator, old_model);
		R_Free(perm_array);
		R_Free(new_geno);
		R_Free(new_alleles);
		goto finalsteps;
	}