Пример #1
0
SmartPointer<Batch> Batch::getTriangles(const std::vector<int>& triangle_indices)
{
	XgeDebugAssert(this->primitive==Batch::TRIANGLES);

	SmartPointer<Batch> ret(new Batch(*this));
	
	//i need to convert indices to vertices -> to indices to elements in the arrays
	std::vector<int> i2(triangle_indices.size()*2);
	std::vector<int> i3(triangle_indices.size()*3);
	for (int i=0;i<(int)triangle_indices.size();i++)
	{
		i2[i*2+0]=triangle_indices[i]*2+0;
		i2[i*2+1]=triangle_indices[i]*2+1;

		i3[i*3+0]=triangle_indices[i]*3+0;
		i3[i*3+1]=triangle_indices[i]*3+1;
		i3[i*3+2]=triangle_indices[i]*3+2;
	}

	if (this->vertices   ) ret->vertices   .reset(new Vector(i3,this->vertices   ->mem()));
	if (this->normals    ) ret->normals    .reset(new Vector(i3,this->normals    ->mem()));
	if (this->colors     ) ret->colors     .reset(new Vector(i3,this->colors     ->mem()));
	if (this->texture0coords ) ret->texture0coords .reset(new Vector(i2,this->texture0coords ->mem())); //2 because each texcoord has 2 components
	if (this->texture1coords) ret->texture1coords.reset(new Vector(i2,this->texture1coords->mem()));

	return ret;
}
Пример #2
0
void Decoder::Decode()
{
	//safety check
	XgeDebugAssert(tohandle_first>tohandle_last);

	while (pos<buffersize)
	{
		int c=buffer[pos++];

		//the end!
		if (c == '=')
		{
			XgeDebugAssert(char_count==2 || char_count==3);

			if (char_count==2)
			{
				tohandle[0]=((bits >> 10));
				tohandle_first=0;
				tohandle_last =0;
			}
			else
			{
Пример #3
0
void Texture::uploadIfNeeded(GLCanvas& gl)
{
  if (this->gpu)
    return;

  juce::OpenGLContext* context=(juce::OpenGLContext*)gl.getGLContext();

  unsigned int texid;
  glGenTextures(1,&texid);XgeReleaseAssert(texid); 
  glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
  glBindTexture (GL_TEXTURE_2D, texid);
  float maxsize;
  glGetFloatv(GL_MAX_TEXTURE_SIZE,&maxsize); 
  XgeDebugAssert (this->width<=maxsize && this->height<=maxsize);

  unsigned int format=(this->bpp==24)?GL_RGB:(this->bpp==32?GL_RGBA:GL_LUMINANCE);
  unsigned int type=GL_UNSIGNED_BYTE;
  gluBuild2DMipmaps(GL_TEXTURE_2D,this->bpp/8,this->width, this->height,format, type, this->buffer);

  this->gpu=SmartPointer<Texture::Gpu>(new Texture::Gpu(texid));	
}
Пример #4
0
static bool triangleRender(const Triangle2i& triangle,SmartPointer<Texture> _rgb,SmartPointer<Texture> _alpha,Color4f color,const Box2i& box, bool bWrite)
{
	XgeDebugAssert(_rgb->bpp==24 && _alpha->bpp==8 && _rgb->width==_alpha->width && _rgb->height==_alpha->height);

	int x1=triangle.p0.x,y1=triangle.p0.y;
	int x2=triangle.p1.x,y2=triangle.p1.y;
	int x3=triangle.p2.x,y3=triangle.p2.y;

	unsigned char* rgb     =_rgb  ->buffer;
	unsigned char* alpha   =_alpha->buffer;
	int            W       =_rgb  ->width;

	int minx = min3(x1, x2, x3) , maxx = max3(x1, x2, x3);
	int miny = min3(y1, y2, y3) , maxy = max3(y1, y2, y3);

	//must be completely be contained in the current area
	if (!(minx>=box.left() && maxx<=box.right() && miny>=box.bottom() && maxy<=box.top()))
	{
		XgeDebugAssert(!bWrite);
		return false;
	}

	int Sign=(((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1))>=0)?(+1):(-1);

	for(int y = miny; y <= maxy; y++)
	for(int x = minx; x <= maxx; x++)
	{
		// if the pixel is inside....
		if
		(
			(Sign*((x2 - x1) * (y - y1) - (y2 - y1) * (x - x1)) >= 0) &&
			(Sign*((x3 - x2) * (y - y2) - (y3 - y2) * (x - x2)) >= 0) &&
			(Sign*((x1 - x3) * (y - y3) - (y1 - y3) * (x - x3)) >= 0)
		)
		{
			int idx=y*W+x;

			//test if it has already been written
			//note: for each pixel consider also the pixel (-1,0) (+1,0) (0,-1) (0,+1)
			if (!bWrite && (alpha[idx] || alpha[idx-1] || alpha[idx+1] ||alpha[idx-W] || alpha[idx+W]))
				return false;
			
			//if write....
			if (bWrite)
			{
				unsigned char R=(unsigned char)(255.0f*color.r);
				unsigned char G=(unsigned char)(255.0f*color.g);
				unsigned char B=(unsigned char)(255.0f*color.b);

				rgb[idx*3+0] = R;
				rgb[idx*3+1] = G;
				rgb[idx*3+2] = B;

				rgb[(idx-1)*3+0] = rgb[(idx+1)*3+0] = rgb[(idx-W)*3+0] = rgb[(idx+W)*3+0] =R ;
				rgb[(idx-1)*3+1] = rgb[(idx+1)*3+1] = rgb[(idx-W)*3+1] = rgb[(idx+W)*3+1] =G ;
				rgb[(idx-1)*3+2] = rgb[(idx+1)*3+2] = rgb[(idx-W)*3+2]  =rgb[(idx+W)*3+2] =B ;

				//sign as drawn
				alpha [idx  ] = 0x01;
				alpha [idx-1] = 0x01;
				alpha [idx+1] = 0x01;
				alpha [idx-W] = 0x01;
				alpha [idx+W] = 0x01;
			}
		}
	}

	return true;
}
Пример #5
0
static Triangle2i triangleProject(int texturedim,float factor,const Vec3f& v0,const Vec3f& v1,const Vec3f& v2)
{
	Vec3f verts[3]={v0,v1,v2};

	//establish order
	double v01=(verts[1]-verts[0]).module();
	double v12=(verts[2]-verts[1]).module();
	double v20=(verts[0]-verts[2]).module();

	//not valid,invalid triangle!
	if (!v01 || !v12 || !v20)
		return Triangle2i(); //fill with all zeros

	int idx[3];
		 if (v01>=v12 && v01>=v20) {if (v12>=v20) {idx[0]=0;idx[1]=1;idx[2]=2;} else {idx[0]=1;idx[1]=0;idx[2]=2;}}
	else if (v12>=v01 && v12>=v20) {if (v01>=v20) {idx[0]=2;idx[1]=1;idx[2]=0;} else {idx[0]=1;idx[1]=2;idx[2]=0;}}
	else if (v20>=v01 && v20>=v12) {if (v01>=v12) {idx[0]=2;idx[1]=0;idx[2]=1;} else {idx[0]=0;idx[1]=2;idx[2]=1;}}
	else                           {XgeDebugAssert(0);}

	Vec3f vdiff[3]=
	{	
		(verts[idx[1]]-verts[idx[0]]),
		(verts[idx[2]]-verts[idx[1]]),
		(verts[idx[0]]-verts[idx[2]])
	};

	double len[3]={vdiff[0].module(),vdiff[1].module(),vdiff[2].module()};

	//safety check
	XgeDebugAssert(len[0]>=0 && len[1]>=0 && len[2]>=0 && len[0]>=len[1] && len[1]>=len[2]);

	int width=0,middle=0,height=0;
	for (float actual_factor=factor;actual_factor;actual_factor*=0.9f)
	{
		width =(int)(actual_factor*len[0]);
		middle=(int)(actual_factor*fabs(vdiff[0]*vdiff[2]) / len[0]);
		height=(int)(actual_factor*(vdiff[0].cross(vdiff[2]).module()) / len[0]);

		if (width<=0.9f*texturedim && height<=0.9f*texturedim) 
			break;
	}

	//correct (it has to have minimum dimension)
	if (width <2     ) width =2; 
	if (height<2     ) height=2; 
	if (middle==0    ) middle=1; 
	if (middle==width) middle--; 

	//safety check
	XgeDebugAssert(width>=2 && height>=2 && middle>0 && middle<width);

	Triangle2i ret;
	ret.getRefPoint(idx[0]).x=0;
	ret.getRefPoint(idx[0]).y=0;

	ret.getRefPoint(idx[1]).x=width;
	ret.getRefPoint(idx[1]).y=0;

	ret.getRefPoint(idx[2]).x=middle;
	ret.getRefPoint(idx[2]).y=height;

	return ret;
}
Пример #6
0
std::vector< SmartPointer<Batch> > Unwrapper::Unwrap(Mat4f _T1,SmartPointer<Batch> source_batch)
{
	std::vector< SmartPointer<Batch> > ret;

	//return the batch I cannot handle untouched
	if (source_batch->primitive!=Batch::TRIANGLES || !source_batch->vertices || !source_batch->vertices->size())
	{
		ret.push_back(source_batch);
		return ret;
	}

	//second transformation matrix
	Mat4f Matrix= _T1 * source_batch->matrix;

	//create a perfect copy and leave the source batch untouched
	SmartPointer<Batch> batch(new Batch(*source_batch));

	//overwrite texture1 coordinates
	int ntriangles=batch->vertices->size()/9;
	batch->texture1coords.reset(new Array(ntriangles*6));
	batch->texture1.reset();

	float* vertices   = (float*)batch -> vertices    -> c_ptr();
	float* lightcoord = (float*)batch -> texture1coords -> c_ptr();



	//*****************************************************************************
	// step 1: triangleProject and rotate GL_TRIANGLES so the longest edge is horizontal and the top vertex is above the horizontal line
	//******************************************************************************

	//LOG("projecting %d triangles\n",ntriangles);

	for (int T=0;T<ntriangles;T++,vertices+=9)
	{			
		//apply transformation matrix
		Vec3f v0 = Matrix * Vec3f(vertices+0);
		Vec3f v1 = Matrix * Vec3f(vertices+3);
		Vec3f v2 = Matrix * Vec3f(vertices+6);

		Triangle2i triangle=triangleProject(texturedim,factor,v0,v1,v2); //NOTE: for now on I have integer coordinates stored!

		(*lightcoord++)=triangle.p0.x;
		(*lightcoord++)=triangle.p0.y;
		(*lightcoord++)=triangle.p1.x;
		(*lightcoord++)=triangle.p1.y;
		(*lightcoord++)=triangle.p2.x;
		(*lightcoord++)=triangle.p2.y;
	}




	//******************************************************************************
	// step 2: sort the triangle by decreasing height (this is for good placement of GL_TRIANGLES)
	//******************************************************************************

	std::vector<int> order(ntriangles);

	for (int T=0;T<ntriangles;T++) order[T]=T;
		std::sort(order.begin(),order.end(),TriangleSort(batch->texture1coords));

	//******************************************************************************
	// step3: pack continous segment
	//******************************************************************************

	std::vector<int>  cur_indices;
	std::vector<int>  prv_indices;

	lightcoord = (float*)batch -> texture1coords -> c_ptr();


	for (int Torder=0;Torder<ntriangles;Torder++)
	{			
		int  T=order[Torder];

		// get the integer texture coordinates as Vec2i
		Triangle2i triangle
		(
			Vec2i(lightcoord[T*6+0],lightcoord[T*6+1]),
			Vec2i(lightcoord[T*6+2],lightcoord[T*6+3]),
			Vec2i(lightcoord[T*6+4],lightcoord[T*6+5])
		);

		//not valid!= since the projection failed
		if (!triangle.p0.x && !triangle.p0.y && !triangle.p1.x && !triangle.p1.y && !triangle.p2.x && !triangle.p2.y)
			continue;

		//give a random color
		Color4f color=Color4f::randomRGB();

		while (true)
		{
			//try with the current texture
			if (cur.rgb && triangleFits(triangle,cur.rgb,cur.alpha,cur.queue,color))	
			{
				lightcoord[T*6+0]=(float)triangle.p0.x;lightcoord[T*6+1]=(float)triangle.p0.y;
				lightcoord[T*6+2]=(float)triangle.p1.x;lightcoord[T*6+3]=(float)triangle.p1.y;
				lightcoord[T*6+4]=(float)triangle.p2.x;lightcoord[T*6+5]=(float)triangle.p2.y;

				cur_indices.push_back(T*3+0); //here I put indices of vertices (each triangle has 3 vertices)
				cur_indices.push_back(T*3+1);
				cur_indices.push_back(T*3+2);
				break;
			}

			//try to fitTriangle2i with the previous texture (seems to be better to do here!)
			if (prv.rgb && triangleFits(triangle,prv.rgb,prv.alpha,prv.queue,color))
			{
				lightcoord[T*6+0]=(float)triangle.p0.x;lightcoord[T*6+1]=(float)triangle.p0.y;
				lightcoord[T*6+2]=(float)triangle.p1.x;lightcoord[T*6+3]=(float)triangle.p1.y;
				lightcoord[T*6+4]=(float)triangle.p2.x;lightcoord[T*6+5]=(float)triangle.p2.y;

				prv_indices.push_back(T*3+0);
				prv_indices.push_back(T*3+1);
				prv_indices.push_back(T*3+2);
				break;
			}

			//cannot fitTriangle2i in prev or current. New texture needed, drop previous one
			if (prv_indices.size()) 
			{
				ret.push_back(batch->getTriangles(prv_indices));
				ret[ret.size()-1]->texture1=prv.rgb;
			}
			
			//the previous becames the current one
			prv=cur;
			prv_indices=cur_indices;

			//allocate new texture
			
			cur.rgb  .reset(new Texture(texturedim,texturedim,24,0));
			cur.alpha.reset(new Texture(texturedim,texturedim, 8,0));
			cur.rgb->filename="";

			if (texture_template.length())
				cur.rgb->filename=Utils::Format(texture_template.c_str(),(int)new_light_textures.size()).c_str();

			new_light_textures.push_back(cur.rgb);

			//LOG("New texture %d\n",(int)new_light_textures.size());
			
			cur.queue.clear();
			cur.queue.insert(Box2i(Vec2i(1,1),Vec2i(texturedim-2,texturedim-2),0)); //this is the working area
			cur_indices.clear();

		} //while true

	} //for each triangle
	
	//******************************************************************************
	// step4: flush residual
	//******************************************************************************

	if (prv_indices.size()) 
	{
		ret.push_back(batch->getTriangles(prv_indices));
		ret[ret.size()-1]->texture1=prv.rgb;
	}
	
	if (cur_indices .size()) 
	{
		ret.push_back(batch->getTriangles(cur_indices));
		ret[ret.size()-1]->texture1=cur.rgb;
	}

	//******************************************************************************
	//convert back to integer coordinates
	//******************************************************************************

	for (std::vector<SmartPointer<Batch> >::iterator ct=ret.begin();ct!=ret.end();ct++)
	{
		XgeDebugAssert((*ct)->primitive==Batch::TRIANGLES);

		float* t= (float*)(*ct)->texture1coords->c_ptr();

		for (int i=0;i<(int)(*ct)->texture1coords->size();i++)
		{
			int ival=(int)(*t);
			float fval=(float)(0.5f/texturedim+ival/(float)texturedim); //robust conversion from int to float 
			*t++=fval;
		}
	}

	ntriangles_done+=ntriangles;

	//#ifdef _DEBUG
	//LOG("RibBake:: GL_TRIANGLES done %2d (ntextures %d)\n",ntriangles_done,(int)this->new_light_textures.size());
	//#endif 
	return ret;
}
Пример #7
0
static bool triangleFits(Triangle2i& triangle,SmartPointer<Texture> rgb,SmartPointer<Texture> alpha,std::set<Box2i>& queue,Color4f color)
{
	XgeDebugAssert(rgb->width==rgb->height);

	int texturedim=rgb->width;

	int w=triangle.right(); //width of the triangle (after the projection)
	int h=triangle.top();   //height of the triangle (after the projection)

	Box2i allowed_area(Vec2i(1,1),Vec2i(texturedim-2,texturedim-2),0);


	//try to fitTriangle2i
	for (std::set<Box2i>::iterator jt=queue.begin();jt!=queue.end() ;jt++)
	{
		Box2i box=*jt;



		Triangle2i candidates[4]=
		{
			triangle.scale(+1,+1).translate(  box.left(),  box.bottom()), //no mirroring
			triangle.scale(-1,+1).translate(w+box.left(),  box.bottom()), //mirror x
			triangle.scale(+1,-1).translate(  box.left(),h+box.bottom()), //mirror y
			triangle.scale(-1,-1).translate(w+box.left(),h+box.bottom())  //mirror x And mirrory
		};

		if (box.align)
		{
			//must start from the top of the area
			candidates[0]=candidates[0].translate(0,box.top()-candidates[0].top());
			candidates[1]=candidates[1].translate(0,box.top()-candidates[1].top());
			candidates[2]=candidates[2].translate(0,box.top()-candidates[2].top());
			candidates[3]=candidates[3].translate(0,box.top()-candidates[3].top());
		}

		while (candidates[0].right()<box.right())
		{
			//safety check
			XgeDebugAssert(
				   candidates[0].right()==candidates[1].right() 
				&& candidates[1].right()==candidates[2].right() 
				&& candidates[2].right()==candidates[3].right());

			for (int n=0;n<4;n++)
			{
				//first try to triangleRender
				if (triangleRender(candidates[n],rgb,alpha,color,box,false)) 
				{
					//store finally in the texture
					triangleRender(candidates[n],rgb,alpha,color,box,true);
					
					//these are the 2 other areas to find for fitting
					if (box.align)
					{
						Box2i box_right(Vec2i(candidates[n].centerx(),candidates[n].bottom()),Vec2i(box.right(),box.top()             ),1);
						Box2i box_down (Vec2i(box.left(),box.bottom())                       ,Vec2i(box.right(),candidates[n].bottom()-3),1);

						if (box_right.isValid() && allowed_area.contains(box_right)) queue.insert(box_right);
						if (box_down .isValid() && allowed_area.contains(box_down )) queue.insert(box_down );
					}
					else
					{
						Box2i box_right(Vec2i(candidates[n].centerx(),box.bottom() ) , Vec2i(box.right(),candidates[n].top()),0);
						Box2i box_up   (Vec2i(box.left(),candidates[n].top()+3   ) , Vec2i(box.right(),box.top()          ),0);

						if (box_right.isValid() && allowed_area.contains(box_right)) queue.insert(box_right);
						if (box_up   .isValid() && allowed_area.contains(box_up   )) queue.insert(box_up   );

						//special case when I do not want to waste space for the first triangle in row
						if (box.left()==1)
						{
							Box2i box_left (Vec2i(box.left(),box.bottom()),Vec2i(candidates[n].centerx(),candidates[n].top()),1);

							if (box_left.isValid() && allowed_area.contains(box_left)) queue.insert(box_left);
						}
					}

					queue.erase(jt);

					//modify the triangle and return ok
					triangle=candidates[n];
					return true;
				}
				
				//try a little more to the right (1 pixel)
				
				candidates[n]=candidates[n].translate(1,0);
			}
		}	
	} 

	//cannot fitTriangle2i in the texture, return false (the triangle has not been modified)
	return false;

}