예제 #1
0
	void digestBuf()
	{
		// Mangle the data
		for(size_t j = 0; j < 3; j++)
		{
			// Taint the bytes
			GAssert(DIGEST_BYTES >= 32);
			if(m_pTaint)
				Taint_buffer(m_pBuf, m_pTaint + (m_rand.next() % (DIGEST_BYTES - 32)), 32, j);

			// Shuffle the bytes
			shuffleBytes(m_pBuf, DIGEST_BYTES);

			// Hash each 64-bit chunk with sha-512
			unsigned char* pChunk = m_pBuf;
			for(size_t i = 0; i < (DIGEST_BYTES / 64); i++)
			{
				sha512_ctx ctx;
				sha512_begin(&ctx);
				sha512_hash(pChunk, 64, &ctx);
				sha512_end(pChunk, &ctx);
				pChunk += 64;
			}
		}

		// Add it to the hash
		uint64_t* pA = (uint64_t*)m_pBuf;
		uint64_t* pB = (uint64_t*)m_pHash;
		for(size_t i = 0; i < (DIGEST_BYTES / sizeof(uint64_t)); i++)
		{
			(*pB) += (*pA);
			pB++;
			pA++;
		}
	}
예제 #2
0
bool GRegionBorderIterator::look()
{
	switch(m_direction)
	{
		case 0:
			if(m_x < (int)m_pImage->width() - 1)
				return(m_pImage->pixel(m_x + 1, m_y) == m_nRegion);
			else
				return false;
		case 1:
			if(m_y > 0)
				return(m_pImage->pixel(m_x, m_y - 1) == m_nRegion);
			else
				return false;
		case 2:
			if(m_x > 0)
				return(m_pImage->pixel(m_x - 1, m_y) == m_nRegion);
			else
				return false;
		case 3:
			if(m_y < (int)m_pImage->height() - 1)
				return(m_pImage->pixel(m_x, m_y + 1) == m_nRegion);
			else
				return false;
		default:
			GAssert(false); // unexpected direction
	}
	return false;
}
예제 #3
0
	void AddTrainingSample(const int inputValue)
	{
		if(inputValue >= 0 && (size_t)inputValue < m_nValues)
			m_pValueCounts[inputValue]++;
		else
			GAssert(inputValue == UNKNOWN_DISCRETE_VALUE);
	}
예제 #4
0
void GPolynomialSingleLabel::integrate()
{
	if(m_featureDims == 0)
		ThrowError("init has not been called");
	GTEMPBUF(size_t, pCoords, m_featureDims);
	double d;
	for(size_t n = 0; n < m_featureDims; n++)
	{
		// Iterate over the entire lattice of coefficients (except in dimension n)
		GPolynomialLatticeIterator iter(pCoords, m_featureDims, m_nControlPoints, n);
		while(true)
		{
			// Integrate in the n'th dimension
			pCoords[n] = 0;
			m_pCoefficients[calcIndex(pCoords)] = 0;
			for(size_t j = m_nControlPoints - 1; j > 0; j--)
			{
				pCoords[n] = j - 1;
				d = m_pCoefficients[calcIndex(pCoords)];
				pCoords[n] = j;
				size_t index = calcIndex(pCoords);
				GAssert(j < m_nControlPoints - 1 || m_pCoefficients[index] == 0); // There's a non-zero value in a highest-order coefficient. This polynomial, therefore, isn't big enough to hold the integral
				m_pCoefficients[index] = d / j;
			}
			if(!iter.Advance())
				break;
		}
	}
}
예제 #5
0
void GSpinLock::lock(const char* szWhoHoldsTheLock)
{
#ifdef _DEBUG
	time_t t;
	time_t tStartTime = time(&t);
	time_t tCurrentTime;
#endif // _DEBUG

#ifdef WIN32
	while(testAndSet(&m_dwLocked))
#else
	while(0!=pthread_mutex_trylock(&m_mutex))
#endif
	{
#ifdef _DEBUG
		tCurrentTime = time(&t);
		GAssert(tCurrentTime - tStartTime < 10); // Blocked for 10 seconds!
#endif // _DEBUG
		GThread::sleep(0);
	}
#ifndef WIN32
	m_dwLocked = 1;
#endif
#ifdef _DEBUG
	m_szWhoHoldsTheLock = szWhoHoldsTheLock;
#endif // _DEBUG
}
예제 #6
0
// This thread increments the balance a bunch of times.  We use a dilly-dally loop
// instead of just calling Sleep because we want our results to reflect
// random context-switches that can happen at any point whereas Sleep causes the
// context switch to happen immediately which may result it one never happening
// at any other point.
unsigned int TestSpinLockThread(void* pParameter)
{
	struct TestSpinLockThreadStruct* pThreadStruct = (struct TestSpinLockThreadStruct*)pParameter;
	int n, i;
	for(n = 0; n < THREAD_ITERATIONS; n++)
	{
		// Take the lock
		pThreadStruct->pSpinLock->lock("TestSpinLockThread");

		// read the balance
		int nBalance = *pThreadStruct->pBalance;

		// We increment nBalance in this funny way so that a smart optimizer won't
		// figure out that it can remove the nBalance variable from this logic.
		nBalance += pThreadStruct->nOne;

		// Dilly-dally
		for(i = 0; i < 10; i++)
			nBalance++;
		for(i = 0; i < 10; i++)
			nBalance--;

		// update the balance
		*pThreadStruct->pBalance = nBalance;

		// Release the lock
		pThreadStruct->pSpinLock->unlock();
	}

	// Clean up and exit
	GAssert(*pThreadStruct->pExitFlag == false); // expected this to be false
	*pThreadStruct->pExitFlag = true;
	delete(pThreadStruct);
	return 1;
}
예제 #7
0
파일: Resource.cpp 프로젝트: sundoom/glare
	/*
	====================
	remove
	====================
	*/
	VOID Resource::Remove(const CHAR* name)
	{
		CHECK(name);
    std::map<Str, Resource*>::iterator it = s_res_map.find(name);
    if(it == s_res_map.end()) GAssert(VA("Can`t find the resource : %s.", name));
    s_res_map.erase(it);
	}
예제 #8
0
// virtual
double GIncrementalLearnerQAgent::getQValue(const double* pState, const double* pAction)
{
	GVec::copy(m_pBuf, pState, m_senseDims);
	GVec::copy(m_pBuf + m_senseDims, pAction, m_actionDims);
	double out;
	m_pQTable->predict(m_pBuf, &out);
	GAssert(out > -1e200);
	return out;
}
예제 #9
0
void FileHolder::reset(FILE* pFile)
{
	if(m_pFile && pFile != m_pFile)
	{
		if(fclose(m_pFile) != 0)
			GAssert(false);
	}
	m_pFile = pFile;
}
예제 #10
0
void GPolynomialSingleLabel::train(GMatrix& features, GMatrix& labels)
{
	GAssert(labels.cols() == 1);
	init(features.cols());
	GPolynomialRegressCritic critic(this, features, labels);
	//GStochasticGreedySearch search(&critic);
	GMomentumGreedySearch search(&critic);
	search.searchUntil(100, 30, .01);
	setCoefficients(search.currentVector());
	fromBezierCoefficients();
}
예제 #11
0
size_t GPolynomialSingleLabel::calcIndex(size_t* pCoords)
{
	size_t nIndex = 0;
	for(size_t n = m_featureDims - 1; n < m_featureDims; n--)
	{
		nIndex *= m_nControlPoints;
		GAssert(pCoords[n] >= 0 && pCoords[n] < m_nControlPoints); // out of range
		nIndex += pCoords[n];
	}
	return nIndex;
}
예제 #12
0
void GGaussianProcess::trainInnerInner(const GMatrix& features, const GMatrix& labels)
{
	clear();
	GMatrix* pL;
	{
		// Compute the kernel matrix
		GMatrix k(features.rows(), features.rows());
		for(size_t i = 0; i < features.rows(); i++)
		{
			GVec& row = k[i];
			const GVec& a = features[i];
			for(size_t j = 0; j < features.rows(); j++)
			{
				const GVec& b = features[j];
				row[j] = m_weightsPriorVar * m_pKernel->apply(a, b);
			}
		}

		// Add the noise variance to the diagonal of the kernel matrix
		for(size_t i = 0; i < features.rows(); i++)
			k[i][i] += m_noiseVar;

		// Compute L
		pL = k.cholesky(true);
	}
	std::unique_ptr<GMatrix> hL(pL);

	// Compute the model
	m_pLInv = pL->pseudoInverse();
	GMatrix* pTmp = GMatrix::multiply(*m_pLInv, labels, false, false);
	std::unique_ptr<GMatrix> hTmp(pTmp);
	GMatrix* pLTrans = pL->transpose();
	std::unique_ptr<GMatrix> hLTrans(pLTrans);
	GMatrix* pLTransInv = pLTrans->pseudoInverse();
	std::unique_ptr<GMatrix> hLTransInv(pLTransInv);
	m_pAlpha = GMatrix::multiply(*pLTransInv, *pTmp, false, false);
	GAssert(m_pAlpha->rows() == features.rows());
	GAssert(m_pAlpha->cols() == labels.cols());
	m_pStoredFeatures = new GMatrix();
	m_pStoredFeatures->copy(&features);
}
예제 #13
0
bool GRegionAjacencyGraph::areNeighbors(size_t nRegion1, size_t nRegion2)
{
	GAssert(nRegion1 != nRegion2); // same region
	struct GRegion* pRegion1 = m_regions[nRegion1];
	struct GRegionEdge* pEdge;
	for(pEdge = pRegion1->m_pNeighbors; pEdge; pEdge = pEdge->GetNext(nRegion1))
	{
		if(pEdge->GetOther(nRegion1) == nRegion2)
			return true;
	}
	return false;
}
예제 #14
0
	struct GGraphCutEdge* GetNextEdge(int nNode)
	{
		if(nNode == m_nNode1)
			return m_pNext1;
		else if(nNode == m_nNode2)
			return m_pNext2;
		else
		{
			GAssert(false); // This edge isn't connected to that node
			return NULL;
		}
	}
예제 #15
0
	int GetOtherNode(int nNode)
	{
		if(nNode == m_nNode1)
			return m_nNode2;
		else if(nNode == m_nNode2)
			return m_nNode1;
		else
		{
			GAssert(false); // This edge isn't connected to that node
			return -1;
		}
	}
예제 #16
0
	struct GRegionEdge* GetNext(size_t nRegion)
	{
		if(nRegion == m_nRegion1)
			return m_pNext1;
		else if(nRegion == m_nRegion2)
			return m_pNext2;
		else
		{
			GAssert(false); // That region doesn't share this edge
			return NULL;
		}
	}
예제 #17
0
	size_t GetOther(size_t n)
	{
		if(n == m_nRegion1)
			return m_nRegion2;
		else if(n == m_nRegion2)
			return m_nRegion1;
		else
		{
			GAssert(false); // That region doesn't share this edge
			return INVALID_INDEX;
		}
	}
예제 #18
0
void GSparseMatrix::set(unsigned int row, unsigned int col, double val)
{
	GAssert(row < m_rows && col < m_cols); // out of range
	if(val == 0)
	{
		m_pRows[row].erase(col);
		m_pCols[col].erase(row);
	}
	else
	{
		m_pRows[row][col] = val;
		m_pCols[col][row] = val;
	}
}
예제 #19
0
/// Predict the belief vector that will result if the specified action is performed
void TransitionModel::anticipateNextBeliefs(const GVec& beliefs, const GVec& actions, GVec& anticipatedBeliefs)
{
	if(tutor)
		tutor->transition(beliefs, actions, anticipatedBeliefs);
	else
	{
		GAssert(beliefs.size() + actions.size() == model.layer(0).inputs());
		buf.resize(beliefs.size() + actions.size());
		buf.put(0, beliefs);
		buf.put(beliefs.size(), actions);
		model.forwardProp(buf);
		anticipatedBeliefs.copy(beliefs);
		anticipatedBeliefs.addScaled(2.0, model.outputLayer().activation());
		anticipatedBeliefs.clip(-1.0, 1.0);
	}
}
예제 #20
0
GStringChopper::GStringChopper(const char* szString, int nMinLength, int nMaxLength, bool bDropLeadingWhitespace)
{
	GAssert(nMinLength > 0 && nMaxLength >= nMinLength); // lengths out of range
	m_bDropLeadingWhitespace = bDropLeadingWhitespace;
	if(nMinLength <= 0)
		nMinLength = 1;
	if(nMaxLength < nMinLength)
		nMaxLength = nMinLength;
	m_nMinLen = nMinLength;
	m_nMaxLen = nMaxLength;
	m_szString = szString;
	m_nLen = (int)strlen(szString);
	if(m_nLen > nMaxLength)
		m_pBuf = new char[nMaxLength + 1];
	else
		m_pBuf = NULL;
}
예제 #21
0
double GSparseMatrix::get(unsigned int row, unsigned int col)
{
	GAssert(row < m_rows && col < m_cols); // out of range
	if(m_rows >= m_cols)
	{
		It it = m_pRows[row].find(col);
		if(it == m_pRows[row].end())
			return 0;
		return it->second;
	}
	else
	{
		It it = m_pCols[col].find(row);
		if(it == m_pCols[col].end())
			return 0;
		return it->second;
	}
}
예제 #22
0
void GRegionBorderIterator::leap()
{
	switch(m_direction)
	{
		case 0:
			m_x++;
			break;
		case 1:
			m_y--;
			break;
		case 2:
			m_x--;
			break;
		case 3:
			m_y++;
			break;
		default:
			GAssert(false); // unexpected direction
	}
}
예제 #23
0
	virtual void Link(GFunctionParser* pMaster)
	{
		GAssert(false); // This should never be called.
	}
예제 #24
0
파일: Shader.cpp 프로젝트: sundoom/glow
	/*
	====================
	Update
	====================
	*/
	VOID Shader::Update(const GData* data)
	{
		GUARD(Shader::Update);		

		// get the shader config
		GConfigPtr shader_config_ptr = GConfig::Load((CHAR*)data->Ptr());
		CHECK(shader_config_ptr);

		// check it if it is a shader?
		CHECK(Str(shader_config_ptr->GetValue()) == "shader");

		std::map<Str, SAMPLER>samplers;

		// prase the shader`s children
		const GConfig *shader_child_config_ptr = NULL;
		for(U32 i = 0; shader_child_config_ptr = shader_config_ptr->GetChild(i); i++)
		{
			// prase the sampler
			if(Str(shader_child_config_ptr->GetValue()) == "sampler")
			{
				const GConfig *sampler_config_ptr = (const GConfig *)shader_child_config_ptr;

				// get the sampler name
				Str name = sampler_config_ptr->GetAttribute("name"); CHECK(name!="");
				if(samplers.find(name)!=samplers.end())GAssert(VA("The sampler is already exists : %s.",name.c_str()));

				// the new sampler
				SAMPLER sampler;
				sampler.wrap_s = GL_REPEAT;
				sampler.wrap_t = GL_REPEAT;
				sampler.wrap_r = GL_REPEAT;
				sampler.min_filter = GL_REPEAT;
				sampler.mag_filter = GL_REPEAT;

				// get the sampler state
				const GConfig *sampler_child_config_ptr =  NULL;
				for(U32 j = 0; sampler_child_config_ptr = sampler_config_ptr->GetChild(j); j++)
				{
					if(Str(sampler_child_config_ptr->GetValue()) == "wrap_s")
					{
						// get the wrap: s
						Str s = sampler_child_config_ptr->GetText(); CHECK(s!="");
						if(s == "CLAMP_TO_EDGE") sampler.wrap_s = GL_CLAMP_TO_EDGE;
						else if(s == "REPEAT") sampler.wrap_s = GL_REPEAT;
						else if(s == "MIRRORED_REPEAT") sampler.wrap_s = GL_MIRRORED_REPEAT;
						else GAssert(VA("The texture`s wrap(s) value(%s) is unknown.\n", s.c_str()));
					}
					else if(Str(sampler_child_config_ptr->GetValue()) == "wrap_t")
					{
						// get the wrap: t
						Str t = sampler_child_config_ptr->GetText(); CHECK(t!="");
						if(t == "CLAMP_TO_EDGE") sampler.wrap_t = GL_CLAMP_TO_EDGE;
						else if(t == "REPEAT") sampler.wrap_t = GL_REPEAT;
						else if(t == "MIRRORED_REPEAT") sampler.wrap_t = GL_MIRRORED_REPEAT;
						else GAssert(VA("The texture`s wrap(t) value(%s) is unknown.\n", t.c_str()));
					}
					else if(Str(sampler_child_config_ptr->GetValue()) == "wrap_r")
					{
						// get the wrap: r
						Str r = sampler_child_config_ptr->GetText(); CHECK(r!="");
						if(r == "CLAMP_TO_EDGE") sampler.wrap_r = GL_CLAMP_TO_EDGE;
						else if(r == "REPEAT") sampler.wrap_r = GL_REPEAT;
						else if(r == "MIRRORED_REPEAT") sampler.wrap_r = GL_MIRRORED_REPEAT;
						else GAssert(VA("The texture`s wrap(r) value(%s) is unknown.\n", r.c_str()));
					}
					else if(Str(sampler_child_config_ptr->GetValue()) == "min_filter")
					{
						// get the min filter
						Str min = sampler_child_config_ptr->GetText(); CHECK(min!="");
						if(min == "NEAREST") sampler.min_filter = GL_NEAREST;
						else if(min == "LINEAR") sampler.min_filter = GL_LINEAR;
						else if(min == "NEAREST_MIPMAP_NEAREST") sampler.min_filter = GL_NEAREST_MIPMAP_NEAREST;
						else if(min == "NEAREST_MIPMAP_LINEAR") sampler.min_filter = GL_NEAREST_MIPMAP_LINEAR;
						else if(min == "LINEAR_MIPMAP_NEAREST") sampler.min_filter = GL_LINEAR_MIPMAP_NEAREST;
						else if(min == "LINEAR_MIPMAP_LINEAR") sampler.min_filter = GL_LINEAR_MIPMAP_LINEAR;
						else GAssert(VA("The texture`s min filter value(%s) is unknown.\n", min.c_str()));
					}
					else if(Str(sampler_child_config_ptr->GetValue()) == "mag_filter")
					{
						// get the mag filter
						Str mag = sampler_child_config_ptr->GetText(); CHECK(mag!="");
						if(mag == "NEAREST") sampler.mag_filter = GL_NEAREST;
						else if(mag == "LINEAR") sampler.mag_filter = GL_LINEAR;
						else GAssert(VA("The texture`s mag filter value(%s) is unknown.\n", mag.c_str()));
					}
					else
					{
						GAssert(VA("The shader`s sampler(%s)`s keyword(%s) is unknown!", name.c_str(), sampler_child_config_ptr->GetValue()));
					}
				}

				// add it to the table
				samplers.insert(std::make_pair(name, sampler));
			}
			// prase the program
			else if(Str(shader_child_config_ptr->GetValue()) == "program")
			{
				const GConfig*program_config_ptr = (const GConfig*)shader_child_config_ptr;

				// the new program
				PROGRAM program;

				// get the program name
				Str program_name = program_config_ptr->GetAttribute("name"); CHECK(program_name!="");
				for(std::list<PROGRAM>::iterator it = mPrograms.begin(); it != mPrograms.end(); ++it)
				{ if(program_name == it->name) GAssert(VA("The program is already exists : %s.",program_name.c_str())); }
				program.name = program_name;

				// get the program attribs
				Str attribs = program_config_ptr->GetAttribute("attribs"); CHECK(attribs!= "");

				// prase the program`s children
				const CHAR *vs, *fs;
				const GConfig *program_child_config_ptr = NULL;
				for(U32 j = 0; program_child_config_ptr = program_config_ptr->GetChild(j); j++)
				{
					if(Str(program_child_config_ptr->GetValue()) == "vs")
					{
						// get the vs source
						vs = program_child_config_ptr->GetText();
					}
					else if(Str(program_child_config_ptr->GetValue()) == "fs")
					{
						// get the fs source
						fs = program_child_config_ptr->GetText();
					}
					else
					{
						GAssert(VA("The shader`s program(%s)`s keyword(%s) is unknown!", program_name.c_str(), program_child_config_ptr->GetValue()));
					}
				}

				GLint result = 0;

				// compile the program
				program.object = glCreateProgram(); CHECK(program.object);

				// compile the vertex shader
				if(vs && vs != "")
				{
					GLuint handle = glCreateShader(GL_VERTEX_SHADER); CHECK(handle);

					// load the vertex shader source
					glShaderSource(handle, 1, (const GLchar**)&vs, NULL);

					// compile the shader
					glCompileShader(handle);
					glGetShaderiv(handle, GL_COMPILE_STATUS, &result);
					if(result == 0)
					{
						GLsizei size;
						glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &size);
						if(size > 1)
						{
							Str log(size+1,0); GLsizei length;
							glGetShaderInfoLog(handle, size, &length, &log[0]);
							if(length > 0) GAssert(log.c_str());
						}
						GAssert("Fail to compile the vertex shader.\n");
					}

					// attach the shader to the gpu program
					glAttachShader(program.object, handle);
					glDeleteShader(handle);
				}

				// compile the fragment shader
				if(fs && fs != "")
				{
					GLuint handle = glCreateShader(GL_FRAGMENT_SHADER); CHECK(handle);

					// load the fragment shader source
					glShaderSource(handle, 1, (const GLchar**)&fs, NULL);

					// compile the shader
					glCompileShader(handle);
					glGetShaderiv(handle, GL_COMPILE_STATUS, &result);
					if(result == 0) 
					{
						GLsizei size;
						glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &size);
						if(size > 1)
						{
							Str log(size+1,0); GLsizei length;
							glGetShaderInfoLog(handle, size, &length, &log[0]);
							if(length > 0) GAssert(log.c_str());
						}
						GAssert("Fail to compile the fragment shader.\n");
					}

					// attach the shader to the GPU Program
					glAttachShader(program.object, handle);
					glDeleteShader(handle);
				}

				// bind the attributes
				if(attribs.size())
				{
					std::vector<Str>attributes = GTokenize(attribs);
					for(U32 k = 0; k < attributes.size(); k++) glBindAttribLocation(program.object, k, attributes[k].c_str());
				}

				// link the shader to the gpu program
				glLinkProgram(program.object);
				glGetProgramiv(program.object, GL_LINK_STATUS, &result);
				if(result == 0) 
				{
					GLsizei size;
					glGetProgramiv(program.object, GL_INFO_LOG_LENGTH, &size);
					if(size > 1)
					{
						Str log(size+1,0); GLsizei length;
						glGetProgramInfoLog(program.object, size, &length, &log[0]);
						if(length > 0) GAssert(log.c_str());
					}
					GAssert("Fail to link the shader to the gpu program.\n");
				}

				// build the uniform map		
				GLint uniform_count, max_length;
				glGetProgramiv(program.object, GL_ACTIVE_UNIFORMS, &uniform_count);
				glGetProgramiv(program.object, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_length);
				CHAR* uniform_name = GNEW(CHAR[max_length+1]); CHECK(uniform_name);
				for( I32 k = 0; k < uniform_count; k++ )
				{
					// get the uniform info of the program
					GLenum type; GLint size;
					memset(uniform_name,0,(max_length+1)*sizeof(CHAR));
					glGetActiveUniform(program.object, k, max_length, 0, &size, &type, &uniform_name[0]);
					GLint location = glGetUniformLocation(program.object, &uniform_name[0]);
					if(location < 0) continue;

					// add the uniform to the table
					std::map<Str, UNIFORM>::iterator it = mUniforms.find(uniform_name);
					if(it == mUniforms.end())
					{
						UNIFORM uniform;
						uniform.type = type;
						uniform.count = 0;
						it = mUniforms.insert(mUniforms.begin(), std::make_pair(uniform_name,uniform));
					}
					CHECK(it!=mUniforms.end() && it->second.type==type);
					program.uniforms.push_back(std::make_pair(location,&it->second));
				}
				GDELETE([]uniform_name);

				// validate the program
				glValidateProgram(program.object);
				glGetProgramiv(program.object, GL_VALIDATE_STATUS, &result);
				if(result == 0)
				{
					GLsizei size;
					glGetProgramiv(program.object, GL_INFO_LOG_LENGTH, &size);
					if(size > 1)
					{
						Str log(size+1,0); GLsizei length;
						glGetProgramInfoLog(program.object, size, &length, &log[0]);
						if(length > 0) GAssert(log.c_str());
					}
				}

				// add the program to the map
				mPrograms.push_back(program);
			}
			// prase the pass
			else if(Str(shader_child_config_ptr->GetValue()) == "pass")
			{
				const GConfig*pass_config_ptr = (const GConfig*)shader_child_config_ptr;

				// get the pass name
				Str pass_name = pass_config_ptr->GetAttribute("name"); CHECK(pass_name!="");

				// the new pass
				PASS pass;
				pass.program = NULL;
				pass.blend_src = GL_ONE;
				pass.blend_dst = GL_ZERO;
				pass.depth_func = GL_LEQUAL;
				pass.depth_mask = TRUE;
				pass.cull_mode = GL_NONE;

				// prase the pass`s children
				const GConfig *pass_child_config_ptr = NULL;
				for(U32 j = 0; pass_child_config_ptr = pass_config_ptr->GetChild(j); j++)
				{
					if(Str(pass_child_config_ptr->GetValue()) == "program")
					{
						// get the program name
						Str program_name = pass_child_config_ptr->GetAttribute("name"); CHECK(program_name!="");

						// get the program of the pass
						for(std::list<PROGRAM>::iterator it = mPrograms.begin(); it != mPrograms.end(); ++it)
						{ if(program_name == it->name) pass.program = &(*it); }
						CHECK(pass.program);
					}
					else if(Str(pass_child_config_ptr->GetValue()) == "blend")
					{
						// get the blend src
						Str src = pass_child_config_ptr->GetAttribute("src"); CHECK(src!="");
						if(src == "BF_ZERO") pass.blend_src = GL_ZERO;
						else if(src == "BF_ONE") pass.blend_src = GL_ONE;
						else if(src == "BF_DST_COLOR") pass.blend_src = GL_DST_COLOR;
						else if(src == "BF_ONE_MINUS_DST_COLOR") pass.blend_src = GL_ONE_MINUS_DST_COLOR;
						else if(src == "BF_SRC_ALPHA_SATURATE") pass.blend_src = GL_SRC_ALPHA_SATURATE;
						else if(src == "BF_SRC_ALPHA") pass.blend_src = GL_SRC_ALPHA;
						else if(src == "BF_ONE_MINUS_SRC_ALPHA") pass.blend_src = GL_ONE_MINUS_SRC_ALPHA;
						else if(src == "BF_DST_ALPHA") pass.blend_src = GL_DST_ALPHA;
						else if(src == "BF_ONE_MINUS_DST_ALPHA") pass.blend_src = GL_ONE_MINUS_DST_ALPHA;

						// get the blend dst
						Str dst = pass_child_config_ptr->GetAttribute("dst"); CHECK(dst!="");
						if(dst == "BF_ZERO") pass.blend_dst = GL_ZERO;
						else if(dst == "BF_ONE") pass.blend_dst = GL_ONE;
						else if(dst == "BF_SRC_COLOR") pass.blend_dst = GL_SRC_COLOR;
						else if(dst == "BF_ONE_MINUS_SRC_COLOR") pass.blend_dst = GL_ONE_MINUS_SRC_COLOR;
						else if(dst == "BF_SRC_ALPHA") pass.blend_dst = GL_SRC_ALPHA;						
						else if(dst == "BF_ONE_MINUS_SRC_ALPHA") pass.blend_dst = GL_ONE_MINUS_SRC_ALPHA;
						else if(dst == "BF_DST_ALPHA") pass.blend_dst = GL_DST_ALPHA;
						else if(dst == "BF_ONE_MINUS_DST_ALPHA") pass.blend_dst = GL_ONE_MINUS_DST_ALPHA;
					}					
					else if(Str(pass_child_config_ptr->GetValue()) == "depth")
					{
						// get the depth func
						Str func = pass_child_config_ptr->GetAttribute("func"); CHECK(func!="");
						if(func == "CF_NEVER") pass.depth_func = GL_NEVER;
						else if(func == "CF_LESS") pass.depth_func = GL_LESS;
						else if(func == "CF_EQUAL") pass.depth_func = GL_EQUAL;
						else if(func == "CF_LEQUAL") pass.depth_func = GL_LEQUAL;
						else if(func == "CF_GREATER") pass.depth_func = GL_GREATER;
						else if(func == "CF_NOTEQUAL") pass.depth_func = GL_NOTEQUAL;
						else if(func == "CF_GEQUAL") pass.depth_func = GL_GEQUAL;
						else if(func == "CF_ALWAYS") pass.depth_func = GL_ALWAYS;

						// get the depth mask
						Str mask = pass_child_config_ptr->GetAttribute("mask"); CHECK(mask!="");
						pass.depth_mask = (mask == "TRUE") ? TRUE : FALSE;
					}
					else if(Str(pass_child_config_ptr->GetValue()) == "cull")
					{
						// get the cull mode
						Str mode = pass_child_config_ptr->GetAttribute("mode"); CHECK(mode!="");
						if(mode == "CULL_NONE") pass.cull_mode = GL_NONE;
						else if (mode == "CULL_FRONT") pass.cull_mode = GL_FRONT;
						else if (mode == "CULL_BACK") pass.cull_mode = GL_BACK;
					}
					else
					{
						GAssert(VA("The effect`s pass keyword(%s) is unknown!", pass_child_config_ptr->GetValue()));
					}
				}

				// add the pass to the table
				mPasses.insert(std::make_pair(pass_name,pass));
			}
			else
			{
				GAssert(VA("The shader`s keyword(%s) is unknown!", shader_child_config_ptr->GetValue()));
			}
		}
예제 #25
0
파일: Shader.cpp 프로젝트: sundoom/glow
	/*
	====================
	BindPass
	====================
	*/
	BOOL Shader::BindPass(const CHAR* name)
	{
		GUARD(Shader::BindPass);

		CHECK(name);

		// get the pass
		std::map<Str, PASS>::iterator it1 = mPasses.find(name);
		if(it1 == mPasses.end()) return FALSE;
		PASS& pass = it1->second;

		// bind the program
		PROGRAM* program = pass.program;
		CHECK(program&&program->object);
		mRCPtr->BindProgram(program->object);

		// update the constant of the program
		GLint texture_unit = 0;
		for(std::list< std::pair<I32, UNIFORM*> >::iterator it = program->uniforms.begin(); it != program->uniforms.end(); ++it)
		{
			const I32& location = it->first;
			UNIFORM*uniform = it->second;
			switch(uniform->type)
			{
			case GL_FLOAT:
				glUniform1fv(location, uniform->count, (GLfloat*)&uniform->data[0]);
				break;
			case GL_FLOAT_VEC2:
				glUniform2fv(location, uniform->count, (GLfloat*)&uniform->data[0]);
				break;
			case GL_FLOAT_VEC3:
				glUniform3fv(location, uniform->count, (GLfloat*)&uniform->data[0]);
				break;
			case GL_FLOAT_VEC4:
				glUniform4fv(location, uniform->count, (GLfloat*)&uniform->data[0]);
				break;
			case GL_INT:
				glUniform1iv(location, uniform->count, (GLint*)&uniform->data[0]);
				break;
			case GL_INT_VEC2:
				glUniform2iv(location, uniform->count, (GLint*)&uniform->data[0]);
				break;
			case GL_INT_VEC3:
				glUniform3iv(location, uniform->count, (GLint*)&uniform->data[0]);
				break;
			case GL_INT_VEC4:
				glUniform4iv(location, uniform->count, (GLint*)&uniform->data[0]);
				break;
			case GL_FLOAT_MAT2:
				glUniformMatrix2fv(location, uniform->count, GL_FALSE, (GLfloat*)&uniform->data[0]);
				break;
			case GL_FLOAT_MAT3:
				glUniformMatrix3fv(location, uniform->count, GL_FALSE, (GLfloat*)&uniform->data[0]);
				break;
			case GL_FLOAT_MAT4:
				glUniformMatrix4fv(location, uniform->count, GL_FALSE, (GLfloat*)&uniform->data[0]);
				break;
			case GL_SAMPLER_2D:
			case GL_SAMPLER_CUBE:
				{
					// get the texture unit
					U32 unit = texture_unit++;

					// set the sampler
					CHECK(uniform->sampler.texture);
					uniform->sampler.texture->WrapS(uniform->sampler.wrap_s);
					uniform->sampler.texture->WrapT(uniform->sampler.wrap_t);
					uniform->sampler.texture->MinFilter(uniform->sampler.min_filter);
					uniform->sampler.texture->MagFilter(uniform->sampler.mag_filter);

					// bind the texture
					uniform->sampler.texture->Bind(mRCPtr.Ptr(), unit);

					// set the unit to the shader
					glUniform1i(location, unit);
				}
				break;
#if 0
			case GL_SAMPLER_3D_OES:
				{
					// get the texture unit
					U32 unit = texture_unit++;

					// get the volume texture			
					VolumeTexture* volume_texture = dynamic_cast<VolumeTexture*>(uniform->sampler.texture.Ptr());
					CHECK(volume_texture);

					// set the sampler
					volume_texture->WrapS(uniform->sampler.wrap_s);
					volume_texture->WrapT(uniform->sampler.wrap_t);
					volume_texture->WrapR(uniform->sampler.wrap_r);
					volume_texture->MinFilter(uniform->sampler.min_filter);
					volume_texture->MagFilter(uniform->sampler.mag_filter);

					// bind the texture
					volume_texture->Bind(mRCPtr.Ptr(), unit);

					// set the unit to the shader
					glUniform1i(location, unit);
				}
				break;
#endif
			default:
				GAssert(VA("The type(%d) of uniform is error!\n", uniform->type));
				break;	
			}
		}			

		// bind depth function and the depth mask if neccesary
		mRCPtr->BindDepthFunc(pass.depth_func);
		mRCPtr->BindDepthMask(pass.depth_mask);

		// bind blending function if neccesary
		mRCPtr->BindBlendFunc(pass.blend_src, pass.blend_dst);

		// bind face culling if neccesary
		mRCPtr->BindCullFunc(pass.cull_mode);

		return TRUE;

		UNGUARD;
	}
예제 #26
0
GTempBufSentinel::~GTempBufSentinel()
{
	GAssert(*(char*)m_pBuf == 'S'); // buffer overrun!
}
예제 #27
0
void loadPng(GImage* pImage, const unsigned char* pData, size_t nDataSize)
{
	// Check for the PNG signature
	if(nDataSize < 8 || png_sig_cmp((png_bytep)pData, 0, 8) != 0)
		throw Ex("not a png file");

	// Read all PNG data up until the image data chunk.
	GPNGReader reader(pData);
	png_set_read_fn(reader.m_pReadStruct, (png_voidp)&reader, (png_rw_ptr)readFunc);
	png_read_info(reader.m_pReadStruct, reader.m_pInfoStruct);

	// Get the image data
	int depth, color;
	png_uint_32 width, height;
	png_get_IHDR(reader.m_pReadStruct, reader.m_pInfoStruct, &width, &height, &depth, &color, NULL, NULL, NULL);
	GAssert(depth == 8); // unexpected depth
	pImage->setSize(width, height);

	// Set gamma correction
	double dGamma;
	if (png_get_gAMA(reader.m_pReadStruct, reader.m_pInfoStruct, &dGamma))
		png_set_gamma(reader.m_pReadStruct, 2.2, dGamma);
	else
		png_set_gamma(reader.m_pReadStruct, 2.2, 1.0 / 2.2); // 1.0 = viewing gamma, 2.2 = screen gamma

	// Update the 'info' struct with the gamma information
	png_read_update_info(reader.m_pReadStruct, reader.m_pInfoStruct);

	// Tell it to expand palettes to full channels
	png_set_expand(reader.m_pReadStruct);
	png_set_gray_to_rgb(reader.m_pReadStruct);

	// Allocate the row pointers
	unsigned long rowbytes = png_get_rowbytes(reader.m_pReadStruct, reader.m_pInfoStruct);
	unsigned long channels = rowbytes / width;
	ArrayHolder<unsigned char> hData(new unsigned char[rowbytes * height]);
	png_bytep pRawData = (png_bytep)hData.get();
	unsigned int i;
	{
		ArrayHolder<unsigned char> hRows(new unsigned char[sizeof(png_bytep) * height]);
		png_bytep* pRows = (png_bytep*)hRows.get();
		for(i = 0; i < height; i++)
			pRows[i] = pRawData + i * rowbytes;
		png_read_image(reader.m_pReadStruct, pRows);
	}

	// Copy to the GImage
	unsigned long nPixels = width * height;
	unsigned int* pRGBQuads = pImage->pixels();
	unsigned char *pBytes = pRawData;
	if(channels > 3)
	{
		GAssert(channels == 4); // unexpected number of channels
		for(i = 0; i < nPixels; i++)
		{
			*pRGBQuads = gARGB(pBytes[3], pBytes[0], pBytes[1], pBytes[2]);
			pBytes += channels;
			pRGBQuads++;
		}
	}
	else if(channels == 3)
	{
		for(i = 0; i < nPixels; i++)
		{
			*pRGBQuads = gARGB(0xff, pBytes[0], pBytes[1], pBytes[2]);
			pBytes += channels;
			pRGBQuads++;
		}
	}
	else
	{
		throw Ex("Sorry, loading ", to_str(channels), "-channel pngs not supported");
/*		GAssert(channels == 1); // unexpected number of channels
		for(i = 0; i < nPixels; i++)
		{
			*pRGBQuads = gARGB(0xff, pBytes[0], pBytes[0], pBytes[0]);
			pBytes += channels;
			pRGBQuads++;
		}*/
	}

	// Check for additional tags
	png_read_end(reader.m_pReadStruct, reader.m_pEndInfoStruct);
}
예제 #28
0
void GSubImageFinder2::findSubImage(int* pOutX, int* pOutY, GImage* pNeedle, GRect* pNeedleRect)
{
	// Fill a vector of candidate offsets with every possible offset
	vector<GSIFStats*> cands;
	cands.reserve((m_pHaystack->height() - pNeedleRect->h) * (m_pHaystack->width() - pNeedleRect->w));
	VectorOfPointersHolder<GSIFStats> hCands(cands);
	for(unsigned int y = 0; y + pNeedleRect->h <= m_pHaystack->height(); y++)
	{
		for(unsigned int x = 0; x + pNeedleRect->w <= m_pHaystack->width(); x++)
		{
			GSIFStats* pStats = new GSIFStats();
			cands.push_back(pStats);
			pStats->m_x = x;
			pStats->m_y = y;
			pStats->m_lastPassIter = 0;
			pStats->m_sse = 0;
		}
	}

	// Measure pixel differences until we can narrow the candidate set down to just one
	GSIFStatsComparer comparer;
	size_t ranges[2];
	ranges[0] = pNeedleRect->w;
	ranges[1] = pNeedleRect->h;
	GCoordVectorIterator cvi(2, ranges); // This chooses which pixel to try next
	for(unsigned int iters = 0; true; iters++)
	{
		// Do another pixel (penalize each candidate for any difference in that pixel)
		size_t best = INVALID_INDEX;
		size_t* pCoords = cvi.current();
		GAssert(pCoords[0] < (size_t)pNeedleRect->w && pCoords[1] < (size_t)pNeedleRect->h);
		unsigned int n = pNeedle->pixel((int)pCoords[0], (int)pCoords[1]);
		for(vector<GSIFStats*>::iterator it = cands.begin(); it != cands.end(); it++)
		{
			GSIFStats* pStats = *it;
			size_t* pCoords = cvi.current();
			unsigned int h = m_pHaystack->pixel((int)pStats->m_x + (int)pCoords[0], (int)pStats->m_y + (int)pCoords[1]);
			int dif;
			dif = gRed(h) - gRed(n);
			pStats->m_sse += (dif * dif);
			dif = gGreen(h) - gGreen(n);
			pStats->m_sse += (dif * dif);
			dif = gBlue(h) - gBlue(n);
			pStats->m_sse += (dif * dif);
			if(pStats->m_sse < best)
			{
				best = pStats->m_sse;
				*pOutX = pStats->m_x;
				*pOutY = pStats->m_y;
			}
		}

		// Divide into the best and worst halves
		vector<GSIFStats*>::iterator median = cands.begin() + (cands.size() / 2);
		std::nth_element(cands.begin(), median, cands.end(), comparer);

		// Ensure that the best half will survive for a while longer
		for(vector<GSIFStats*>::iterator it = cands.begin(); it != median; it++)
		{
			GSIFStats* pStats = *it;
			pStats->m_lastPassIter = iters;
		}

		// Kill off candidates that have been in the worst half for too long
		for(size_t i = median - cands.begin(); i < cands.size(); i++)
		{
			if(iters - cands[i]->m_lastPassIter >= 32)
			{
				size_t last = cands.size() - 1;
				delete(cands[i]);
				std::swap(cands[i], cands[last]);
				cands.erase(cands.begin() + last);
				i--;
			}
		}

		// Pick the next pixel (using a well-distributed sampling technique)
		if(!cvi.advanceSampling() || cands.size() == 1)
			break;
	}

	// Return the results
	vector<GSIFStats*>::iterator itBest = std::min_element(cands.begin(), cands.end(), comparer);
	*pOutX = (*itBest)->m_x;
	*pOutY = (*itBest)->m_y;
}
예제 #29
0
void GSubImageFinder::findSubImage(int* pOutX, int* pOutY, GImage* pNeedle, GRect* pNeedleRect, GRect* pHaystackRect)
{
	// Copy into the array of complex numbers
	GAssert(GBits::isPowerOfTwo(pNeedleRect->w) && GBits::isPowerOfTwo(pNeedleRect->h)); // Expected a power of 2
	int x, y;
	int pos = 0;
	unsigned int c;
	for(y = 0; y < pNeedleRect->h; y++)
	{
		for(x = 0; x < pNeedleRect->w; x++)
		{
			c = pNeedle->pixel(pNeedleRect->x + x, pNeedleRect->y + y);
			m_pNeedleRed[pos].real = gRed(c) - 128;
			m_pNeedleRed[pos].imag = 0;
			m_pNeedleGreen[pos].real = gGreen(c) - 128;
			m_pNeedleGreen[pos].imag = 0;
			m_pNeedleBlue[pos].real = gBlue(c) - 128;
			m_pNeedleBlue[pos].imag = 0;
			pos++;
		}
	}

	// Convert to the Fourier domain
	GFourier::fft2d(pNeedleRect->w, pNeedleRect->h, m_pNeedleRed, true);
	GFourier::fft2d(pNeedleRect->w, pNeedleRect->h, m_pNeedleGreen, true);
	GFourier::fft2d(pNeedleRect->w, pNeedleRect->h, m_pNeedleBlue, true);

	// Multiply m_pHaystack with the complex conjugate of m_pNeedle
	double r, i, mag;
	int xx, yy;
	pos = 0;
	for(y = 0; y < m_nHaystackHeight; y++)
	{
		yy = (y * pNeedleRect->h / m_nHaystackHeight) * pNeedleRect->w;
		for(x = 0; x < m_nHaystackWidth; x++)
		{
			xx = x * pNeedleRect->w / m_nHaystackWidth;
			r = m_pNeedleRed[yy + xx].real * m_pHaystackRed[pos].real + m_pNeedleRed[yy + xx].imag * m_pHaystackRed[pos].imag;
			i = m_pNeedleRed[yy + xx].real * m_pHaystackRed[pos].imag - m_pNeedleRed[yy + xx].imag * m_pHaystackRed[pos].real;
			mag = sqrt(r * r + i * i);
			m_pCorRed[pos].real = r / mag;
			m_pCorRed[pos].imag = i / mag;
			r = m_pNeedleGreen[yy + xx].real * m_pHaystackGreen[pos].real + m_pNeedleGreen[yy + xx].imag * m_pHaystackGreen[pos].imag;
			i = m_pNeedleGreen[yy + xx].real * m_pHaystackGreen[pos].imag - m_pNeedleGreen[yy + xx].imag * m_pHaystackGreen[pos].real;
			mag = sqrt(r * r + i * i);
			m_pCorGreen[pos].real = r / mag;
			m_pCorGreen[pos].imag = i / mag;
			r = m_pNeedleBlue[yy + xx].real * m_pHaystackBlue[pos].real + m_pNeedleBlue[yy + xx].imag * m_pHaystackBlue[pos].imag;
			i = m_pNeedleBlue[yy + xx].real * m_pHaystackBlue[pos].imag - m_pNeedleBlue[yy + xx].imag * m_pHaystackBlue[pos].real;
			mag = sqrt(r * r + i * i);
			m_pCorBlue[pos].real = r / mag;
			m_pCorBlue[pos].imag = i / mag;
			pos++;
		}
	}

	// Convert to the Spatial domain
	GFourier::fft2d(m_nHaystackWidth, m_nHaystackHeight, m_pCorRed, false);
	GFourier::fft2d(m_nHaystackWidth, m_nHaystackHeight, m_pCorGreen, false);
	GFourier::fft2d(m_nHaystackWidth, m_nHaystackHeight, m_pCorBlue, false);

	// Find the max
	*pOutX = 0;
	*pOutY = 0;
	double d;
	double dBest = -1e200;
	for(y = 0; y < pHaystackRect->h; y++)
	{
		yy = m_nHaystackY + pHaystackRect->y + y;
		if(yy < 0 || yy >= m_nHaystackHeight) // todo: precompute range instead
			continue;
		yy *= m_nHaystackWidth;
		for(x = 0; x < pHaystackRect->w; x++)
		{
			xx = m_nHaystackX + pHaystackRect->x + x;
			if(xx < 0 || xx >= m_nHaystackWidth) // todo: precompute range instead
				continue;
			xx += yy;
			d = m_pCorRed[xx].real * m_pCorGreen[xx].real * m_pCorBlue[xx].real;
			if(d > dBest)
			{
				dBest = d;
				*pOutX = pHaystackRect->x + x;
				*pOutY = pHaystackRect->y + y;
			}
		}
	}
/*
	// Save correlation image
	GImage corr;
	corr.setSize(m_nHaystackWidth, m_nHaystackHeight);
	pos = 0;
	for(y = 0; y < m_nHaystackHeight; y++)
	{
		for(x = 0; x < m_nHaystackWidth; x++)
		{
			d = m_pCorRed[pos].real * m_pCorGreen[pos].real * m_pCorBlue[pos].real;
			corr.setPixel(x, y, gFromGray(MAX((int)0, (int)(d * 255 * 256 / dBest))));
			pos++;
		}
	}
	corr.savePng("correlat.png");
*/
}
예제 #30
0
void G2DRegionGraph::makeCoarserRegions(G2DRegionGraph* pFineRegions)
{
	// Find every region's closest neighbor
	GImage* pFineRegionMask = pFineRegions->regionMask();
	GImage* pCoarseRegionMask = regionMask();
	GAssert(pCoarseRegionMask->width() == pFineRegionMask->width() && pCoarseRegionMask->height() == pFineRegionMask->height()); // size mismatch
	int* pBestNeighborMap = new int[pFineRegions->regionCount()];
	ArrayHolder<int> hBestNeighborMap(pBestNeighborMap);
	for(size_t i = 0; i < pFineRegions->regionCount(); i++)
	{
		struct GRegion* pRegion = pFineRegions->m_regions[i];
		struct GRegionEdge* pEdge;
		double d;
		double dBestDiff = 1e200;
		int nBestNeighbor = -1;
		for(pEdge = pRegion->m_pNeighbors; pEdge; pEdge = pEdge->GetNext(i))
		{
			size_t j = pEdge->GetOther(i);
			struct GRegion* pOtherRegion = pFineRegions->m_regions[j];
			d = MeasureRegionDifference(pRegion, pOtherRegion);
			if(d < dBestDiff)
			{
				dBestDiff = d;
				nBestNeighbor = (int)j;
			}
		}
		GAssert(nBestNeighbor != -1 || pFineRegions->regionCount() == 1); // failed to find a neighbor
		pBestNeighborMap[i] = nBestNeighbor;
	}

	// Create a mapping to new regions numbers
	int* pNewRegionMap = new int[pFineRegions->regionCount()];
	ArrayHolder<int> hNewRegionMap(pNewRegionMap);
	memset(pNewRegionMap, 0xff, sizeof(int) * pFineRegions->regionCount());
	int nNewRegionCount = 0;
	for(size_t i = 0; i < pFineRegions->regionCount(); i++)
	{
		size_t nNewRegion = -1;
		size_t j = i;
		while(pNewRegionMap[j] == -1)
		{
			pNewRegionMap[j] = -2;
			j = pBestNeighborMap[j];
		}
		if(pNewRegionMap[j] == -2)
			nNewRegion = nNewRegionCount++;
		else
			nNewRegion = pNewRegionMap[j];
		j = i;
		while(pNewRegionMap[j] == -2)
		{
			pNewRegionMap[j] = (int)nNewRegion;
			j = pBestNeighborMap[j];
		}
	}

	// Make the new regions
	for(size_t i = 0; i < pFineRegions->regionCount(); i++)
	{
		struct GRegion* pRegion = pFineRegions->m_regions[i];
		size_t j = pNewRegionMap[i];
		if(regionCount() <= j)
		{
			GAssert(regionCount() == j); // how'd it get two behind?
			addRegion();
		}
		struct GRegion* pCoarseRegion = m_regions[j];
		pCoarseRegion->m_nSumRed += pRegion->m_nSumRed;
		pCoarseRegion->m_nSumGreen += pRegion->m_nSumGreen;
		pCoarseRegion->m_nSumBlue += pRegion->m_nSumBlue;
		pCoarseRegion->m_nPixels += pRegion->m_nPixels;
	}
	for(size_t i = 0; i < pFineRegions->regionCount(); i++)
	{
		struct GRegion* pRegion = pFineRegions->m_regions[i];
		size_t j = pNewRegionMap[i];
		struct GRegionEdge* pEdge;
		for(pEdge = pRegion->m_pNeighbors; pEdge; pEdge = pEdge->GetNext(i))
		{
			size_t k = pNewRegionMap[pEdge->GetOther(i)];
			if(j != k)
				makeNeighbors(j, k);
		}
	}

	// Make the fine region mask
	unsigned int nOldRegion;
	int x, y;
	for(y = 0; y < (int)pFineRegionMask->height(); y++)
	{
		for(x = 0; x < (int)pFineRegionMask->width(); x++)
		{
			nOldRegion = pFineRegionMask->pixel(x, y);
			pCoarseRegionMask->setPixel(x, y, pNewRegionMap[nOldRegion]);
		}
	}
}