예제 #1
0
TEST(ReadPng, Png_Monochrome) {
  Image<unsigned char> image;
  string png_filename = string(THIS_SOURCE_DIR) + "/image_test/two_pixels_monochrome.png";
  EXPECT_TRUE(ReadImage(png_filename.c_str(), &image));
  EXPECT_EQ(2, image.Width());
  EXPECT_EQ(1, image.Height());
  EXPECT_EQ(1, image.Depth());
  EXPECT_EQ(image(0,0), (unsigned char)255);
  EXPECT_EQ(image(0,1), (unsigned char)0);
}
예제 #2
0
TEST(ReadJpg, Jpg_Color) {
  Image<RGBColor> image;
  string jpg_filename = string(THIS_SOURCE_DIR) + "/image_test/two_pixels_color.jpg";
  EXPECT_TRUE(ReadImage(jpg_filename.c_str(), &image));
  EXPECT_EQ(2, image.Width());
  EXPECT_EQ(1, image.Height());
  EXPECT_EQ(3, image.Depth());
  EXPECT_EQ(image(0,0), RGBColor(255, 125, 11));
  EXPECT_EQ(image(0,1), RGBColor( 20, 127, 255));
}
예제 #3
0
TEST(ReadPnm, PgmComments) {
  Image<unsigned char> image;
  string pgm_filename = string(THIS_SOURCE_DIR) + "/image_test/two_pixels_gray.pgm";
  EXPECT_TRUE(ReadImage(pgm_filename.c_str(), &image));
  EXPECT_EQ(2, image.Width());
  EXPECT_EQ(1, image.Height());
  EXPECT_EQ(1, image.Depth());
  EXPECT_EQ(image(0,0), (unsigned char)255);
  EXPECT_EQ(image(0,1), (unsigned char)0);
}
예제 #4
0
TEST(ReadPnm, Ppm) {
  Image<RGBColor> image;
  string ppm_filename = string(THIS_SOURCE_DIR) + "/image_test/two_pixels.ppm";
  EXPECT_TRUE(ReadImage(ppm_filename.c_str(), &image));
  EXPECT_EQ(2, image.Width());
  EXPECT_EQ(1, image.Height());
  EXPECT_EQ(3, image.Depth());
  EXPECT_EQ(image(0,0), RGBColor( (unsigned char)255));
  EXPECT_EQ(image(0,1), RGBColor( (unsigned char)0));
}
예제 #5
0
TEST(ReadPng, Png_Color) {
  Image<RGBAColor> image;
  string png_filename = string(THIS_SOURCE_DIR) + "/image_test/two_pixels_color.png";
  EXPECT_TRUE(ReadImage(png_filename.c_str(), &image));
  // Depth is 4 (RGBA by default)
  EXPECT_EQ(2, image.Width());
  EXPECT_EQ(1, image.Height());
  EXPECT_EQ(4, image.Depth());
  EXPECT_EQ(image(0,0), RGBAColor(255, 125, 10, 255));
  EXPECT_EQ(image(0,1), RGBAColor( 20, 127, 255,255));
}
void CMeanFilter_GPU::Apply(const Image& input, Image& output)
{
	const int radius = CFilterParameterInterpreter<int>::Convert(_parameters->GetParameter("Radius"));
	const int width = input.Width();
	const int height = input.Height();
	const int NbPixel = width * height;
	const int depth = input.Depth();
	const unsigned char *image_data = input.Data();
	unsigned char *output_data = output.Data();

	//int *TempPix = new int[ NbPixel * 2 ];
	unsigned char *TempMask = new unsigned char[NbPixel];
	//memset( TempPix, 0, NbPixel * 2 * sizeof( int ) );
	memset(TempMask, 255, NbPixel * sizeof(unsigned char));

	auto current_device = OpenCLUtils::Instance()->GetCurrentDevice();
	const cl::Context Context = current_device.Context();

	cl_int Error;
	cl_mem_flags InOutMemFlags = CL_MEM_READ_WRITE;
	cl_mem_flags InMemFlags = CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR;
	cl_mem_flags OutMemFlags = CL_MEM_WRITE_ONLY;

	// If you ever change the local size, don't forget to change the size in the kernel
	// Global size must be a multiple of local size
	unsigned int GlobalSizeY = height;
	unsigned int GlobalSizeX = width;

	cl::Buffer ImBuffer(Context, InMemFlags, NbPixel * depth * sizeof(unsigned char), (void*)image_data, &Error);
	cl::Buffer MaskBuffer(Context, InMemFlags, NbPixel * sizeof(unsigned char), (void*)TempMask, &Error);
	cl::Buffer OutBuffer(Context, OutMemFlags, NbPixel * depth * sizeof(unsigned char), 0, &Error);

	cl::CommandQueue Queue = current_device.CommandQueue();
	cl::Event Event;

	// Horizontal pass
	int Index = 0;
	m_KernelH.setArg(Index++, ImBuffer);
	m_KernelH.setArg(Index++, MaskBuffer);
	m_KernelH.setArg(Index++, OutBuffer);
	m_KernelH.setArg(Index++, height);
	m_KernelH.setArg(Index++, width);
	m_KernelH.setArg(Index++, radius);

	Queue.enqueueNDRangeKernel(m_KernelH, cl::NullRange, cl::NDRange(GlobalSizeX, GlobalSizeY), cl::NullRange, 0, &Event);
	Event.wait();

	Queue.enqueueReadBuffer(OutBuffer, true, 0, NbPixel * depth * sizeof(unsigned char), (void*)output_data, 0, &Event);
	Event.wait();

	Queue.finish();

	delete[] TempMask;
}
예제 #7
0
//template<typename ImageOut>
static void rgbFloat2rgbInt(
        const Image< RGBfColor >& imaIn,
        Image< RGBColor > *imaOut,
        float factor = 255.f )
{
  assert( imaIn.Depth() == 3 );
  (*imaOut).resize(imaIn.Width(), imaIn.Height());
  // Convert each int RGB to float RGB values
  for( int j = 0; j < imaIn.Height(); ++j )
    for( int i = 0; i < imaIn.Width(); ++i )
      convertFloatToInt( imaIn( j, i ), (*imaOut)( j, i ), factor  );
}
예제 #8
0
double GetTypeRange(const Image& Img)
{
   switch (Img.Depth())
   {
   case 8:
      return 0xFF;
   case 16:
      return 0xFFFF;
   case 32:
      if (Img.IsFloat())
         return 0xFF;

      return 0xFFFFFFFF;
   default:
      assert(false); // Wrong type used
      return 1;
   }

}
예제 #9
0
double GetTypeMin(const Image& Img)
{
   if (Img.IsUnsigned())
      return 0;

   if (Img.IsFloat())
      return 0;

   switch (Img.Depth())
   {
   case 8:
      return -128.;
   case 16:
      return -32768.;
   case 32:
      return -2147483648.;
   default:
      assert(false); // Wrong type used
      return 0;
   }

}
void CMeanFilter_GPUPad::Apply(const Image& input, Image& output)
{
	const int radius = CFilterParameterInterpreter<int>::Convert(_parameters->GetParameter("Radius"));
	const int GroupSize = 32;
	const int width = input.Width();
	const int height = input.Height();
	const int depth = input.Depth();
	const int NbPixel = width * height;
	const uchar *image_data = input.Data();
	uchar *output_data = output.Data();
	const int NewHeight = Utils::GetNextMultipleOf(height, GroupSize) + radius * 2 + GroupSize;
	const int NewWidth = Utils::GetNextMultipleOf(width, GroupSize) + radius * 2 + GroupSize;
	const int NewNbPixel = NewHeight * NewWidth;

	Image NewImage(NewWidth, NewHeight, depth);
	int *TempPix = new int[NewNbPixel * 2 * depth];
	unsigned char *TempMask = new unsigned char[NewNbPixel];
	Image NewOut(NewWidth, NewHeight, depth);
	memset(TempPix, 0, NewNbPixel * 2 * depth * sizeof(int));
	memset(TempMask, 0, NewNbPixel * sizeof(unsigned char));

	// Copy image into subrect
	int NewImageIndex = 0;
	int OldImageIndex = 0;
	int temp_val = 0;
	for (int i = 0; i < height; ++i)
	{
		for (int j = 0; j < width; ++j)
		{
			for (int k = 0; k < depth; ++k)
			{
				NewImage(i + radius,j + radius,k) = input(i,j,k);
			}
			TempMask[(i+radius) * NewWidth + j + radius] = 1;
		}
	}

	auto current_device = OpenCLUtils::Instance()->GetCurrentDevice();
	const cl::Context Context = current_device.Context();

	cl_int Error;
	cl_mem_flags InOutMemFlags = CL_MEM_READ_WRITE;
	cl_mem_flags InMemFlags = CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR;
	cl_mem_flags OutMemFlags = CL_MEM_WRITE_ONLY;

	// If you ever change the local size, don't forget to change the size in the kernel
	unsigned int LocalSizeY = 1;
	unsigned int LocalSizeX = GroupSize;
	// Global size must be a multiple of local size
	unsigned int GlobalSizeY = (height + LocalSizeY - 1) / LocalSizeY;
	GlobalSizeY *= LocalSizeY;
	unsigned int GlobalSizeX = (width + LocalSizeX - 1) / LocalSizeX;
	GlobalSizeX *= LocalSizeX;

	cl::Buffer ImBuffer(Context, InMemFlags, NewNbPixel * depth * sizeof(unsigned char), (void*)NewImage.Data(), &Error);
	cl::Buffer MaskBuffer(Context, InMemFlags, NewNbPixel * sizeof(unsigned char), (void*)TempMask, &Error);
	cl::Buffer ImTempBuffer(Context,
		InOutMemFlags, NewNbPixel * 2 * depth * sizeof(int),
		0, &Error);
	cl::Buffer OutBuffer(Context, OutMemFlags, NewNbPixel * depth * sizeof(unsigned char), 0, &Error);

	cl::CommandQueue Queue = current_device.CommandQueue();
	cl::Event Event;

	// Zero out temp buffer
	m_KernelZero.setArg(0, ImTempBuffer);
	Queue.enqueueNDRangeKernel(m_KernelZero, cl::NullRange, cl::NDRange(NewNbPixel), cl::NullRange, 0, &Event);
	Event.wait();

	// Horizontal pass
	int Index = 0;
	m_KernelH.setArg(Index++, ImBuffer);
	m_KernelH.setArg(Index++, MaskBuffer);
	m_KernelH.setArg(Index++, ImTempBuffer);
	m_KernelH.setArg(Index++, NewHeight);
	m_KernelH.setArg(Index++, NewWidth);
	m_KernelH.setArg(Index++, radius);

	Queue.enqueueNDRangeKernel(m_KernelH, cl::NullRange, cl::NDRange(GlobalSizeX, GlobalSizeY), cl::NDRange(LocalSizeX, LocalSizeY), 0, &Event);
	Event.wait();

	// Vertical pass
	LocalSizeY = GroupSize;
	LocalSizeX = 1;
	// Global size must be a multiple of local size
	GlobalSizeY = (height + LocalSizeY - 1) / LocalSizeY;
	GlobalSizeY *= LocalSizeY;
	GlobalSizeX = (width + LocalSizeX - 1) / LocalSizeX;
	GlobalSizeX *= LocalSizeX;

	Index = 0;
	m_KernelV.setArg(Index++, ImTempBuffer);
	m_KernelV.setArg(Index++, OutBuffer);
	m_KernelV.setArg(Index++, NewHeight);
	m_KernelV.setArg(Index++, NewWidth);
	m_KernelV.setArg(Index++, radius);

	Queue.enqueueNDRangeKernel(m_KernelV, cl::NullRange, cl::NDRange(GlobalSizeY, GlobalSizeX), cl::NDRange(LocalSizeY, LocalSizeX), 0, &Event);
	Event.wait();

	Queue.enqueueReadBuffer(OutBuffer, true, 0, NewNbPixel * depth * sizeof(unsigned char), (void*)NewOut.Data(), 0, &Event);
	Event.wait();

	Queue.finish();

	//PrintToFile( NewOut, (size_t)NewWidth, (size_t)NewHeight, "GPUPad.txt" );

	// Read Sub rect
	for (int i = 0; i < height; ++i)
	{
		for (int j = 0; j < width; ++j)
		{
			for (int k = 0; k < depth; ++k)
			{
				output(i,j,k) = NewOut(i+radius, j+radius,k);
			}
		}
	}

	delete[] TempPix;
	delete[] TempMask;
}
void MeanFilter_CPU::Apply(const Image &input, Image &output)
{
	const int radius = CFilterParameterInterpreter<int>::Convert(_parameters->GetParameter("Radius"));
	const int width = input.Width();
	const int height = input.Height();
	const int depth = input.Depth();
	const unsigned char *data = input.Data();
	unsigned char *out_data = output.Data();

	int i = 0, j = 0, ii = 0, jj = 0;
	int borneInfx = 0, borneSupx = radius + 1;

	std::vector<int> accuYMemoryR; accuYMemoryR.resize(radius + 1, 0);
	std::vector<int> compteurYMemoryR; compteurYMemoryR.resize(radius + 1, 0);
	std::vector<int> accuYMemoryG; accuYMemoryG.resize(radius + 1, 0);
	std::vector<int> compteurYMemoryG; compteurYMemoryG.resize(radius + 1, 0);
	std::vector<int> accuYMemoryB; accuYMemoryB.resize(radius + 1, 0);
	std::vector<int> compteurYMemoryB; compteurYMemoryB.resize(radius + 1, 0);

	int index = 0;

	int nbpt_R = 0;
	int nbpttemp_R = 0;
	int sommetemp_R = 0;
	int somme_R = 0;
	int compteurligneY_R = 0;
	int sommeligneY_R = 0;
	int valtemp_R = 0;

	int nbpt_G = 0;
	int nbpttemp_G = 0;
	int sommetemp_G = 0;
	int somme_G = 0;
	int compteurligneY_G = 0;
	int sommeligneY_G = 0;
	int valtemp_G = 0;

	int nbpt_B = 0;
	int nbpttemp_B = 0;
	int sommetemp_B = 0;
	int somme_B = 0;
	int compteurligneY_B = 0;
	int sommeligneY_B = 0;
	int valtemp_B = 0;


	// Initialisation
	for (jj = 0; jj < radius + 1; jj++){
		for (ii = 0; ii < radius + 1; ii++){
			index = (jj * width + ii) * depth;

			valtemp_R = int(data[index]);
			accuYMemoryR[jj] = accuYMemoryR[jj] + valtemp_R; // Somme des valeurs horizontalement
			compteurYMemoryR[jj] = compteurYMemoryR[jj] + 1;
			somme_R += valtemp_R;
			nbpt_R += 1;

			valtemp_G = int(data[index + 1]);
			accuYMemoryG[jj] = accuYMemoryG[jj] + valtemp_G; // Somme des valeurs horizontalement
			compteurYMemoryG[jj] = compteurYMemoryG[jj] + 1;
			somme_G += valtemp_G;
			nbpt_G += 1;

			valtemp_B = int(data[index + 2]);
			accuYMemoryB[jj] = accuYMemoryB[jj] + valtemp_B; // Somme des valeurs horizontalement
			compteurYMemoryB[jj] = compteurYMemoryB[jj] + 1;
			somme_B += valtemp_B;
			nbpt_B += 1;
		}
	}

	std::vector<int> compteurY_R; compteurY_R.resize(radius + 1, 0);
	std::vector<int> accuY_R; accuY_R.resize(radius + 1, 0);

	std::vector<int> compteurY_G; compteurY_G.resize(radius + 1, 0);
	std::vector<int> accuY_G; accuY_G.resize(radius + 1, 0);

	std::vector<int> compteurY_B; compteurY_B.resize(radius + 1, 0);
	std::vector<int> accuY_B; accuY_B.resize(radius + 1, 0);

	// Boucle principale
	for (i = 0; i < width; ++i){
		accuY_R = accuYMemoryR;
		compteurY_R = compteurYMemoryR;
		accuY_G = accuYMemoryG;
		compteurY_G = compteurYMemoryG;
		accuY_B = accuYMemoryB;
		compteurY_B = compteurYMemoryB;

		sommetemp_R = somme_R;
		nbpttemp_R = nbpt_R;
		sommetemp_G = somme_G;
		nbpttemp_G = nbpt_G;
		sommetemp_B = somme_B;
		nbpttemp_B = nbpt_B;

		index = 0;

		if (nbpttemp_R != 0){
			out_data[i * depth] = (unsigned char)((double)sommetemp_R / (double)nbpttemp_R);
		}
		if (nbpttemp_G != 0){
			out_data[i * depth + 1] = (unsigned char)((double)sommetemp_G / (double)nbpttemp_G);
		}
		if (nbpttemp_B != 0){
			out_data[i * depth + 2] = (unsigned char)((double)sommetemp_B / (double)nbpttemp_B);
		}

		borneInfx = (i - radius > 0) ? (i - radius) : 0; // ATTENTION
		borneSupx = (i + radius + 1 < width) ? (i + radius + 1) : width;


		for (j = 1; j < height; ++j){

			jj = j + radius;

			// Si on peut entrer une nouvelle ligne
			if (jj < height){
				for (ii = borneInfx; ii < borneSupx; ii++){
					sommeligneY_R += int(data[(jj * width + ii) * depth]);
					compteurligneY_R++;
					sommeligneY_G += int(data[(jj * width + ii) * depth + 1]);
					compteurligneY_G++;
					sommeligneY_B += int(data[(jj * width + ii) * depth + 2]);
					compteurligneY_B++;
				}
				sommetemp_R += sommeligneY_R;
				nbpttemp_R += compteurligneY_R;
				accuY_R.push_back(sommeligneY_R);
				compteurY_R.push_back(compteurligneY_R);
				sommeligneY_R = 0;
				compteurligneY_R = 0;

				sommetemp_G += sommeligneY_G;
				nbpttemp_G += compteurligneY_G;
				accuY_G.push_back(sommeligneY_G);
				compteurY_G.push_back(compteurligneY_G);
				sommeligneY_G = 0;
				compteurligneY_G = 0;

				sommetemp_B += sommeligneY_B;
				nbpttemp_B += compteurligneY_B;
				accuY_B.push_back(sommeligneY_B);
				compteurY_B.push_back(compteurligneY_B);
				sommeligneY_B = 0;
				compteurligneY_B = 0;
			}

			// Si on ne touche plus le bord
			if ((j - radius) > 0){
				sommetemp_R -= accuY_R[index];
				nbpttemp_R -= compteurY_R[index];

				sommetemp_G -= accuY_G[index];
				nbpttemp_G -= compteurY_G[index];

				sommetemp_B -= accuY_B[index];
				nbpttemp_B -= compteurY_B[index];

				index++;
			}

			if (nbpttemp_R != 0){
				out_data[(j * width + i) * depth] = (unsigned char)((double)sommetemp_R / (double)nbpttemp_R);
			}
			if (nbpttemp_G != 0){
				out_data[(j * width + i) * depth + 1] = (unsigned char)((double)sommetemp_G / (double)nbpttemp_G);
			}
			if (nbpttemp_B != 0){
				out_data[(j * width + i) * depth + 2] = (unsigned char)((double)sommetemp_B / (double)nbpttemp_B);
			}
		}


		// Reinitialisation
		accuY_R.resize(radius + 1, 0);
		compteurY_R.resize(radius + 1, 0);
		accuY_G.resize(radius + 1, 0);
		compteurY_G.resize(radius + 1, 0);
		accuY_B.resize(radius + 1, 0);
		compteurY_B.resize(radius + 1, 0);
		index = 0;

		if (i - radius >= 0){
			for (jj = 0; jj < (radius + 1) && jj < height; jj++){
				valtemp_R = int(data[(jj * width + borneInfx) * depth]);
				accuYMemoryR[jj] -= valtemp_R;// accuYMemory[jj] - valtemp;
				compteurYMemoryR[jj]--;// = compteurYMemory[jj] - 1;
				somme_R -= valtemp_R;
				nbpt_R--;

				valtemp_G = int(data[(jj * width + borneInfx) * depth + 1]);
				accuYMemoryG[jj] -= valtemp_G;// accuYMemory[jj] - valtemp;
				compteurYMemoryG[jj]--;// = compteurYMemory[jj] - 1;
				somme_G -= valtemp_G;
				nbpt_G--;

				valtemp_B = int(data[(jj * width + borneInfx) * depth + 2]);
				accuYMemoryB[jj] -= valtemp_B;// accuYMemory[jj] - valtemp;
				compteurYMemoryB[jj]--;// = compteurYMemory[jj] - 1;
				somme_B -= valtemp_B;
				nbpt_B--;
			}
		}

		if (borneSupx < width){
			for (jj = 0; jj < (radius + 1) && jj < height; jj++){
				valtemp_R = int(data[(jj * width + borneSupx) * depth]);
				accuYMemoryR[jj] += valtemp_R;// accuYMemory[jj] + valtemp;
				compteurYMemoryR[jj]++;// = compteurYMemory[jj] + 1;
				somme_R += valtemp_R;
				nbpt_R++;

				valtemp_G = int(data[(jj * width + borneSupx) * depth + 1]);
				accuYMemoryG[jj] += valtemp_G;// accuYMemory[jj] + valtemp;
				compteurYMemoryG[jj]++;// = compteurYMemory[jj] + 1;
				somme_G += valtemp_G;
				nbpt_G++;

				valtemp_B = int(data[(jj * width + borneSupx) * depth + 2]);
				accuYMemoryB[jj] += valtemp_B;// accuYMemory[jj] + valtemp;
				compteurYMemoryB[jj]++;// = compteurYMemory[jj] + 1;
				somme_B += valtemp_B;
				nbpt_B++;
			}
		}
	}
}
예제 #12
0
파일: Game.cpp 프로젝트: sundoom/sunstudio
/*
====================
build
====================
*/
VOID Game::build()
{
    GUARD(Game::build);

    // build the color texture
    Image* image = GNEW(Image);
    CHECK(image);
    image->Width(256);
    image->Height(256);
    image->Depth(1);
    image->PixelFormat(PF_RGBA);
    image->DataType(DT_UNSIGNED_BYTE);
    mColorTexPtr = GNEW(Texture);
    CHECK(mColorTexPtr);
    mColorTexPtr->Load(image);

    // build the color rt
    mColorRTPtr = GNEW(Target(mColorTexPtr.Ptr()));
    CHECK(mColorRTPtr);

    // build the primitive
    mQuadPtr = GNEW(Primitive);
    CHECK(mQuadPtr);
    mQuadPtr->SetType(Primitive::PT_TRIANGLES);

    // set the wvp
    Constant* wvp_constant_ptr = GNEW(Constant);
    CHECK(wvp_constant_ptr);
    wvp_constant_ptr->SetMatrix(Matrix());
    mQuadPtr->SetConstant("gWVP",wvp_constant_ptr);

    // set the color texture
    Constant* texture_constant_ptr = GNEW(Constant);
    CHECK(texture_constant_ptr);
    texture_constant_ptr->SetTexture(mColorTexPtr.Ptr());
    mQuadPtr->SetConstant("gBaseTex",texture_constant_ptr);

    // set the shader
    Str shader_key_name = "shader/default.xml";
    KeyPtr shader_key_ptr = Key::Find(shader_key_name.c_str());
    if(shader_key_ptr == NULL)
    {
        Shader*shader = GNEW(Shader);
        CHECK(shader);
        shader->Load(GLoad(shader_key_name.c_str()));
        shader_key_ptr = GNEW(Key(shader_key_name.c_str(), shader));
        CHECK(shader_key_ptr);
    }
    mKeys.push_back(shader_key_ptr);
    mQuadPtr->SetShader(dynamic_cast<Shader*>(shader_key_ptr->Ptr()),"p0");

    // build the vertex buffer
    F32 x = 0.0f, y = 0.0f, w = 256, h = 256;
    DVT vertexes[] =
    {
        {x,		y,		0,		0,		0},
        {x+w,	y,		0,		1,		0},
        {x+w,	y+h,	0,		1,		1},
        {x,		y+h,	0,		0,		1},
    };
    VertexBufferPtr vb_ptr = GNEW(VertexBuffer);
    CHECK(vb_ptr);
    {
        GDataPtr vd_ptr = GNEW(GData);
        CHECK(vd_ptr);
        vd_ptr->Size(3*sizeof(U32) + 3*sizeof(U8) + sizeof(vertexes));
        U8*data_ptr = (U8*)vd_ptr->Ptr();
        *(U32*)data_ptr = MAKEFOURCC('G','V','B','O');
        data_ptr += sizeof(U32);
        *(U32*)data_ptr = sizeof(vertexes)/sizeof(DVT);
        data_ptr += sizeof(U32);
        *(U32*)data_ptr = sizeof(DVT);
        data_ptr += sizeof(U32);
        *(U8*)data_ptr = 2;
        data_ptr += sizeof(U8);
        *(U8*)data_ptr = VertexBuffer::VT_3F;
        data_ptr += sizeof(U8);
        *(U8*)data_ptr = VertexBuffer::VT_2F;
        data_ptr += sizeof(U8);
        ::memcpy(data_ptr, vertexes, sizeof(vertexes));
        data_ptr += sizeof(vertexes);
        vb_ptr->Load(vd_ptr.Ptr());
    }
    mQuadPtr->SetVertexBuffer(vb_ptr.Ptr());

    // build the index
    const U16 indexes[] = { 3, 0, 2, 2, 0, 1 };
    IndexBufferPtr ib_ptr = GNEW(IndexBuffer);
    CHECK(ib_ptr);
    {
        GDataPtr id_ptr = GNEW(GData);
        CHECK(id_ptr);
        id_ptr->Size(3*sizeof(U32) + sizeof(indexes));
        U8*data_ptr = (U8*)id_ptr->Ptr();
        *(U32*)data_ptr = MAKEFOURCC('G','I','B','O');
        data_ptr += sizeof(U32);
        *(U32*)data_ptr = sizeof(indexes)/sizeof(U16);
        data_ptr += sizeof(U32);
        *(U32*)data_ptr = sizeof(U16);
        data_ptr += sizeof(U32);
        ::memcpy(data_ptr, &indexes[0], sizeof(indexes));
        data_ptr += sizeof(indexes);
        ib_ptr->Load(id_ptr.Ptr());
    }
    mQuadPtr->SetIndexBuffer(ib_ptr.Ptr());

    // build the bounding box
    BoundingBox box;
    box.set(MAX_F32,MAX_F32,MAX_F32,MIN_F32,MIN_F32,MIN_F32);
    for(U32 i = 0; i < sizeof(vertexes)/sizeof(DVTN); i++)box.expand(vertexes[i].point);
    mQuadPtr->SetBox(box);

    UNGUARD;
}