view TaskManager/Test/test_render/polygon.cpp @ 130:40978d4b608a draft

テクスチャの大きさを128x128以外にも使えるように。(若干バグ有り)
author gongo@gendarme.cr.ie.u-ryukyu.ac.jp
date Tue, 25 Nov 2008 17:19:43 +0900
parents e9e12e2088bd
children 91c74dbc32e4
line wrap: on
line source

#include <iostream>
#include <SDL.h>
#include <SDL_opengl.h>
#include <SDL_image.h>
#include <libxml/parser.h>
#include "polygon.h"
#include "xml.h"
#include "texture.h"
#include "sys.h"
#include "triangle.h"
#include "vertex.h"
#include "Span.h"
#include "SpanC.h"
#include "scene_graph_pack.h"
#include "error.h"
#include "viewer_types.h"
using namespace std;

//extern int decode(char *cont, char *file_name);
extern int decode(char *cont, FILE *outfile);


SDL_Surface* Polygon::texture_image;

Polygon::Polygon()
{
  xyz[0] = 0;
  xyz[1] = 0;
  xyz[2] = 0;
  xyz[3] = 1;
  c_xyz[0] = 0;
  c_xyz[1] = 0;
  c_xyz[2] = 0;
  c_xyz[3] = 1;
  angle[0] = 0;
  angle[1] = 0;
  angle[2] = 0;
  angle[3] = 1;
  next = NULL;
  parent = NULL;
  brother = NULL;
  children = NULL;
  lastChild = NULL;
}



void Polygon::tree_check()
{
  Polygon *t;
  t = this;

  while(t)
    {
      cout << "my_name : " << t->name << endl;
      if(t->children != NULL)
	{
	  cout << "--move children : " << t->children->name << endl;
	  t = t->children;
	}
      else if(t->brother != NULL)
	{
	  cout << "--move brother : " << t->brother->name << endl;
	  t = t->brother;
	}
      else
	{
	  while(t)
	    {
	      if(t->brother != NULL)
		{
		  cout << "--move brother : " << t->brother->name << endl;
		  t = t->brother;
		  break;
		}
	      else
		{
		  if(t->parent)
		    {
		      cout << "--move parent : " << t->parent->name << endl;
		    }
		  t = t->parent;
		}
	    }
	}
    }
}

void Polygon::print_member()
{
  //int n;

  cout << "size = " << size << endl;
  cout << "name = " << name << endl;
  cout << "parent_name = " << parent_name << endl;
  /*
  for(n=0; n<size*3; n+=3)
    {
      cout<<"coordinate = "<<data[n]<<" "<<data[n+1]<<" "<< data[n+2]<<endl;
    }
  */
  /*
  for(n=size*3; n<size*6; n+=3)
    {
      cout<<"narmal = "<<data[n]<<" "<<data[n+1]<<" "<<data[n+2]<<endl;
    }
  */
  cout<<"c_xyz = "<<c_xyz[0]<<" "<<c_xyz[1]<<" "<<c_xyz[2]<<endl;
  /*
  for(n=size*6; n<size*9; n+=3)
    {
      cout<<"texture = "<<data[n]<<" "<<data[n+1]<<" "<<data[n+2]<<endl;
    }
  */
  /*
  for(n=0; n<size*3; n+=3)
    {
      cout<<"coordinate = "<<data[n]<<" "<<data[n+1]<<" "<<data[n+2]<<endl;
      cout<<"normal = "<<data[n+size*3]<<" "<<data[n+size*3+1]<<" "<<data[n+size*3+2]<<endl;
      cout<<"texture = "<<data[n+size*6]<<" "<<1-data[n+size*6+1]<<endl;
    }
  */
  //cout << "image_name = " << image_name << endl;
  if(parent != NULL)
    {
      cout << "parent->name = " << parent->name << endl;
    }
  if(children != NULL)
    {
      cout << "children->name = " << children->name << endl;
    }
}

void Polygon::draw(SceneGraphPack *sgp)
{
  float xyz1[4],xyz2[4],xyz3[4];

  /***SceneGraphUpdate***/
  //sgp_update();
  for (int i = 0; i < sgp->info.size; i++) {
    SceneGraphNode node = sgp->node[i];

    /***draw***/
    int n,nt;
    for(n=0,nt=0; n<node.size*3; n+=9,nt+=6) {
      xyz1[0] = node.vertex[n];
      xyz1[1] = node.vertex[n+1];
      xyz1[2] = node.vertex[n+2]*-1;
      xyz1[3] = 1;
      xyz2[0] = node.vertex[n+3];
      xyz2[1] = node.vertex[n+3+1];
      xyz2[2] = node.vertex[n+3+2]*-1;
      xyz2[3] = 1;
      xyz3[0] = node.vertex[n+6];
      xyz3[1] = node.vertex[n+6+1];
      xyz3[2] = node.vertex[n+6+2]*-1;
      xyz3[3] = 1;

      rotate(xyz1, node.translation);
      rotate(xyz2, node.translation);
      rotate(xyz3, node.translation);

      Vertex *ver1 = new Vertex(xyz1[0],xyz1[1],xyz1[2],node.texture[nt],node.texture[nt+1]);
      Vertex *ver2 = new Vertex(xyz2[0],xyz2[1],xyz2[2],node.texture[nt+2],node.texture[nt+2+1]);
      Vertex *ver3 = new Vertex(xyz3[0],xyz3[1],xyz3[2],node.texture[nt+4],node.texture[nt+4+1]);

      Triangle *tri = new Triangle(ver1,ver2,ver3);
      Span_c *span = new Span_c();
      span->viewer = viewer;
      span->p = this;
      span->create_span(tri,texture_image);
      delete ver1;
      delete ver2;
      delete ver3;
      delete tri;
      delete span;
    }
  }
}


void Polygon::draw(PolygonPack *pp)
{
  for(int n=0; n<pp->info.size; n++)
    {
      Vertex *ver1 = new Vertex(pp->tri[n].ver1.x,pp->tri[n].ver1.y,pp->tri[n].ver1.z,pp->tri[n].ver1.tex_x,pp->tri[n].ver1.tex_y);
      Vertex *ver2 = new Vertex(pp->tri[n].ver2.x,pp->tri[n].ver2.y,pp->tri[n].ver2.z,pp->tri[n].ver2.tex_x,pp->tri[n].ver2.tex_y);
      Vertex *ver3 = new Vertex(pp->tri[n].ver3.x,pp->tri[n].ver3.y,pp->tri[n].ver3.z,pp->tri[n].ver3.tex_x,pp->tri[n].ver3.tex_y);

      Triangle *tri = new Triangle(ver1,ver2,ver3);
      Span_c *span = new Span_c();
      span->viewer = viewer;
      span->p = this;
      span->create_span(tri,texture_image);
      delete ver1;
      delete ver2;
      delete ver3;
      delete tri;
      delete span;
    }
}

void Polygon::draw(SpanPack *sp)
{
    Span *span;

    for (int n = 0; n < sp->info.size; n++) {
	span = &sp->span[n];

	//int x = span->x;
	//int y = span->y;
	float z = span->start_z;
	int end = span->length_x;
	float zpos = span->end_z;
	float tex1 = span->tex_x1;
	float tex2 = span->tex_x2;
	float tey1 = span->tex_y1;
	float tey2 = span->tex_y2;
	Uint32 rgb;
	int tex_xpos;
	int tex_ypos;
	int tex_zpos;
	float tex_x, tex_y, tex_z;

	if (end == 1) {
	    tex_xpos = (int)((span->tex_height-1) * tex1);
	    tex_ypos = (int)((span->tex_width-1) * tey1);
	    tex_zpos = (int)z;
	    rgb = get_rgb(tex_xpos, tex_ypos);
	    //viewer->write_pixel(x, y, zpos, rgb);
	} else {
	    for (int j = 0; j < end; j++) {
		tex_x = tex1*(end-1-j)/(end-1) + tex2*j/(end-1);
		tex_y = tey1*(end-1-j)/(end-1) + tey2*j/(end-1);
		tex_z = z*(end-1-j)/(end-1) + zpos*j/(end-1);
		if (tex_x > 1) tex_x = 1;
		if (tex_y > 1) tex_y = 1;
		tex_xpos = (int)((span->tex_height-1) * tex_x);
		tex_ypos = (int)((span->tex_width-1) * tex_y);
		rgb = get_rgb(tex_xpos,tex_ypos);
		//viewer->write_pixel(j + x, y, tex_z, rgb);
	    }
	}
    }
}

void Polygon::add_next()
{
  Polygon *p;
  p = new Polygon;

  next = p;
}


void Polygon::create_tree()
{
  Polygon *list;
  Polygon *check_list;
  Polygon *p;
  Polygon *bros;

  check_list = this;

  for (list=this; list; list=list->next) {
      if (xmlStrcmp((xmlChar *)list->parent_name, (xmlChar *)"NULL")) {
	  p = this;

	  while (p) {
	      if (!xmlStrcmp((xmlChar *)p->name,(xmlChar *)list->parent_name))
	      {
		  list->parent = p;
		  if(p->children == NULL)
		  {
		      p->children = list;
		  }
		  else
		  {
		      bros = p->children;
		      while(bros->brother != NULL)
		      {
			  bros = bros->brother;
		      }
		      bros->brother = list;
		  }		  
		  break;
	      }
	      p = p->next;
	  }
      }
  }
}

void Polygon::pickup_coordinate(char *cont)
{
  for(int n=0; n<size*3; n+=3)
    {
      cont = pickup_float(cont, data+n);
      cont = pickup_float(cont, data+n+1);
      cont = pickup_float(cont, data+n+2);
      
      if (cont == NULL)
	{
	  cout << "Analyzing obj data failed coordinate\n";
	}
    }
}

void Polygon::pickup_normal(char *cont)
{
  for(int n=size*3;n<size*6;n+=3)
    {
      cont = pickup_float(cont,data+n);
      cont = pickup_float(cont,data+n+1);
      cont = pickup_float(cont,data+n+2);
      
      if (cont == NULL)
	{
	  cout << "Analyzing obj data failed normal\n";
	}
    }
}

void Polygon::pickup_model(char *cont)
{
  cont = pickup_float(cont,c_xyz);
  cont = pickup_float(cont,c_xyz+1);
  cont = pickup_float(cont,c_xyz+2);
  
  if (cont == NULL)
    {
      cout << "Analyzing obj data failed model\n";
    }
}

void Polygon::pickup_texture(char *cont)
{
  for(int n=size*6; n<size*9; n+=3)
    {
      cont = pickup_float(cont,data+n);
      cont = pickup_float(cont,data+n+1);
      data[n+2] = 1.0;
      
      if (cont == NULL)
	{
	  cout << "Analyzing obj data failed texture\n";
	}
    }
}

char *get_pixel(int tx, int ty, SDL_Surface *texture_image)
{
  return (char*)texture_image->pixels+(texture_image->format->BytesPerPixel*((texture_image->w)*ty+tx));
}

unsigned my_ntohl(unsigned u) {
  //     rr gg bb 00
  //           rr
  //     bb gg rr
  //unsigned u1 =   ((u&0xff)<<24) +
  //         ((u&0xff00)<<8) +
  //         ((u&0xff0000)>>8) +
  //         ((u&0xff000000)>>24);
  unsigned u1;
  unsigned b = (u&0xff000000)>>24;
  unsigned g = (u&0xff0000)>>16;
  unsigned r = (u&0xff00)>>8;
  u1 = r + (g<<8) + (b<<16);
  //printf("pixel %x->%x\n",u,u1);
  return u1;
}

Uint32 Polygon::get_rgb(int tx, int ty)
{
  SDL_PixelFormat *fmt;
  //Uint32 temp, pixel;
  Uint8 red, green, blue;
  
  fmt = texture_image->format;

  if (tx<0) tx = 0;
  if (texture_image->w-1< tx) tx = texture_image->w-1 ;
  if (ty<0) ty = 0;
  if (texture_image->h-1< ty) ty = texture_image->h-1 ;



  //SDL_LockSurface(texture_image);
  char *p = get_pixel(tx,ty,texture_image);
#if 0
  pixel = my_ntohl(*(Uint32*)p);
  //printf("pixel = %d\n", pixel);
  //printf("pixel %x bpp = %d ",p, fmt->BytesPerPixel);
  //SDL_UnlockSurface(texture_image);
  
  temp = pixel&fmt->Rmask;
  temp = temp>>fmt->Rshift;
  temp = temp<<fmt->Rloss;
  red = (Uint8)temp;
  
  temp = pixel&fmt->Gmask;
  temp = temp>>fmt->Gshift;
  temp = temp<<fmt->Gloss;
  green = (Uint8)temp;
  
  temp = pixel&fmt->Bmask;
  temp = temp>>fmt->Bshift;
  temp = temp<<fmt->Bloss;
  blue = (Uint8)temp;
#endif
  blue  = (Uint8) p[0];
  green = (Uint8) p[1];
  red   = (Uint8) p[2];
	  
  //printf("tx = %d ty = %d ", tx,ty); 
  //printf("pixel color =>  R: %d,  G: %d,  B: %d\n", red, green, blue);

  SDL_PixelFormat *pf;
  //pf = viewer->screen->format;

  //cout << SDL_MapRGB(pf, red, green, blue) << endl;
  return SDL_MapRGB(pf, red, green, blue);
}


/*
 * surface nodeからポリゴンの情報を読み出す 再帰しない
 */
void Polygon::get_data(xmlNodePtr cur)
{
  char *cont;
  //char *image_name;

  for(;cur;cur=cur->next)
    {
      if(!xmlStrcmp(cur->name,(xmlChar*)"coordinate"))
        {
          cont = (char *)xmlNodeGetContent(cur);
	  pickup_coordinate(cont);
        }
      else if(!xmlStrcmp(cur->name,(xmlChar*)"normal"))
        {
          cont = (char *)xmlNodeGetContent(cur);
	  pickup_normal(cont);
        }
      else if(!xmlStrcmp(cur->name,(xmlChar*)"model"))
        {
          cont = (char *)xmlNodeGetContent(cur);
	  pickup_model(cont);
        }
      else if(!xmlStrcmp(cur->name,(xmlChar*)"texture"))
        {
          cont = (char *)xmlNodeGetContent(cur);
	  pickup_texture(cont);
	}
      else if(!xmlStrcmp(cur->name,(xmlChar*)"image"))
        {
	  char image_name[20] = "/tmp/image_XXXXXX";
	  int fd = mkstemp(image_name);
	  FILE *outfile = fdopen(fd, "wb");
	  if(NULL == outfile)
	    {
	      cout << "error open file\n";
	    }
          cont = (char *)xmlNodeGetContent(cur);
          //decode(cont, image_name);
	  decode(cont, outfile);
	  fclose(outfile);

	  texture_image = IMG_Load(image_name);

	  /**
	   * image を 32bit(RGBA) に変換する
	   */
	  SDL_Surface *tmpImage
	      = SDL_CreateRGBSurface(SDL_HWSURFACE, texture_image->w,
				     texture_image->h, 32,
				     redMask, greenMask, blueMask, alphaMask);
	  SDL_Surface *converted;
	  converted = SDL_ConvertSurface(texture_image,
					 tmpImage->format, SDL_HWSURFACE);
	  if( converted != NULL){
	      SDL_FreeSurface(texture_image);
	      texture_image = converted;
	  }

	  //load_texture(image_name);
	  if(unlink(image_name))
	    {
	      cout << "unlink error\n";
	    }
        }
    }
}


/*
 * ノードを受け取って、そこからポリゴンを生成
 * リークしてない? data上書きしちゃだめ
 */
void Polygon::create_data(xmlNodePtr cur)
{
    char *p = (char *)xmlGetProp(cur,(xmlChar *)"size");
    //error 出力?

#ifndef _DEBUG
    if(strlen(p)>8){     
	__debug("Polygon size is too large.\n");
	exit(1);
    }
#endif
  
    size = atoi((char *)xmlGetProp(cur,(xmlChar *)"size"));    
    name = (char *)xmlGetProp(cur,(xmlChar *)"name");
    parent_name = (char *)xmlGetProp(cur,(xmlChar *)"parent");
    next = NULL;
    
    data = new float[size*3*3];

    get_data(cur->children);
}

/*
 * xmlをオープンして、Surfaceノードからポリゴンを作る
 *
 */
void Polygon::set_data(char *file_name)
{
  xmlDocPtr doc;
  xmlNodePtr cur;
  Polygon *tmp;

  doc = xmlParseFile(file_name);

  cur = xmlDocGetRootElement(doc);

  xmlStrcmp(cur->name,(xmlChar*)"OBJECT-3D");

  tmp = this;

  for (cur=cur->children; cur; cur=cur->next)
    {
      if (!xmlStrcmp(cur->name,(xmlChar*)"surface"))
        {
	  tmp->create_data(cur);
	  if(cur->next->next)
	    {
	      tmp->add_next();
	      tmp = tmp->next;
	    }
        }
    }

  create_tree();
  //tree_check();
  //create_scene_graph_pack();

  xmlFreeDoc(doc);

  /*
  for(int s=0; s<sgp->info.size; s++)
    {
      printf("sgp->node[%d].pn = %d\n",s,sgp->node[s].pn);
    }
  */
  //delete sgp;
}

void Polygon::delete_data()
{
  Polygon *n,*m;

  n = this;
  delete [] n->data;

  if(next)
    {
      for(n = this->next; n; n=m)
	{
	  m = n->next;
	  delete [] n->data;
	  delete n;
	}
    }
}



/* construct polygon from xml.  */
/*
Polygon::Polygon(char *xmlfile)
{
  Polygon();
  xmlDocPtr doc;
  xmlNodePtr cur;
  Polygon *tmp;

  doc = xmlParseFile(file_name);

  cur = xmlDocGetRootElement(doc);

  xmlStrcmp(cur->name,(xmlChar*)"OBJECT-3D");

  tmp = this;

  for (cur=cur->children; cur; cur=cur->next)
    {
      if ( xmlStrcmp(cur->name,(xmlChar*)"surface")!=0 )
	  continue;

      if ( xmlStrcmp(cur->parent ))
      tmp->create_data(cur);
      if(cur->next->next)
        {
	  tmp->add_next();
	  tmp = tmp->next;
	}
    }

  create_tree();
  //tree_check();
  //create_scene_graph_pack();

  xmlFreeDoc(doc);
}
*/

/* construct polygon from xmlNode.  */
Polygon::Polygon(xmlNodePtr surface)
{
#if 1
  xyz[0] = 0;
  xyz[1] = 0;
  xyz[2] = 0;
  xyz[3] = 1;
  c_xyz[0] = 0;
  c_xyz[1] = 0;
  c_xyz[2] = 0;
  c_xyz[3] = 1;
  angle[0] = 0;
  angle[1] = 0;
  angle[2] = 0;
  angle[3] = 1;
  next = NULL;
  parent = NULL;
  brother = NULL;
  children = NULL;
  lastChild = NULL;
#else
  /* これ使うにはどうすればいいの?  */
  this->Polygon();
#endif
  size = atoi((char *)xmlGetProp(surface,(xmlChar *)"size"));
  name = (char *)xmlGetProp(surface,(xmlChar *)"name");
  parent_name = (char *)xmlGetProp(surface,(xmlChar *)"parent");
  next = NULL;

  data = new float[size*3*3];

  get_data(surface->children);
}

/* XMLファイルからポリゴンを作成  */
Polygon *Polygon::createFromXMLfile(char *xmlfile)
{
    xmlDocPtr doc;
    xmlNodePtr cur;
    Polygon *root=NULL, *tmp, *parent;

    /* パース DOM生成 */
    doc = xmlParseFile(xmlfile);
    cur = xmlDocGetRootElement(doc);

    /* ??  */
    xmlStrcmp(cur->name,(xmlChar*)"OBJECT-3D");

    /* XMLのノードを一つずつ解析  */
    for (cur=cur->children; cur; cur=cur->next)
    {
	/* 扱うのはsurfaceオンリー  */
	if ( xmlStrcmp(cur->name,(xmlChar*)"surface")!=0 )
	    continue;

	/* ポリゴン生成  */
	tmp = new Polygon(cur);
	if ( tmp->parent_name==NULL || 0==strcmp(tmp->parent_name, "NULL")) {
	    /* このsurfaceがroot  */
	    root = tmp;
	} else {
	    /* 親はこのsurfaceより前に定義されているものとする (していい?)  */
	    //  ここで parent_name を用いるのは間違っていて、
	    //   *cur->properties->children から探すべきらしい kono
	    parent = root->searchPolygon(tmp->parent_name);
	    if (parent==NULL) {
		fprintf(stderr, "[%s] No such parent %s\n",
			tmp->name, tmp->parent_name);
		root->addChild(tmp);
	    } else {
		parent->addChild(tmp);
	    }
	}
    }
  
    xmlFreeDoc(doc);
    return root;
}

/* 子供を追加  */
Polygon *Polygon::addChild(Polygon *child)
{
  Polygon *tmp;

  /* childrenのリストの最後に加える */
  if (this->lastChild != NULL) {
      tmp = this->lastChild;
      tmp->children = child;
  }

  this->lastChild = child;

  if (this->children == NULL) {
      this->children = child;
  }

  return child;
}

/* thisの子や子孫にnameのものが存在すればそいつを返す なければNULL.  */
Polygon *Polygon::searchPolygon(char *name)
{
  Polygon *tmp, *result;

  /* 本人か  */
  if( 0==strcmp(this->name, name) ) return this;

  /* 子供から再帰的に探す  */
  for( tmp=this->children; tmp; tmp=tmp->next )
    {
      if( (result=tmp->searchPolygon(name))!=NULL )
	return result;
    }

  /* 無かったら NULL.  */
  return NULL;
}