オフスクリーンレンダリング

「オフスクリーンレンダリング」の編集履歴(バックアップ)一覧はこちら

オフスクリーンレンダリング」(2014/03/01 (土) 22:49:18) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

<p><strong>オフスクリーンレンダリングです。<br /> レースゲームのバックミラーの描画等で使われます。<br /> metasequiaに付属のviolin.mqoを.xに変換して使用しています。<br /><a href="http://cdn21.atwikiimg.com/opengl/pub/png/violin.x">violin.x</a>は<a href="http://cdn21.atwikiimg.com/opengl/pub/png/violin.x">ここ</a>からダウンロードして下さい。<br /> 右クリックして名前を付けてリンク先を保存でダウンロードできます。</strong></p> <p><img alt="" src="http://cdn21.atwikiimg.com/opengl?cmd=upload&amp;act=open&amp;pageid=295&amp;file=off.png" /></p> <p>violin.png</p> <p><img alt="" src="http://www21.atwiki.jp/opengl?cmd=upload&amp;act=open&amp;pageid=295&amp;file=violin.png" /></p> <p> </p> <p> </p> <p> </p> <p> </p> <p> </p>
<p><strong>オフスクリーンレンダリングです。<br /> レースゲームのバックミラーの描画等で使われます。<br /> metasequiaに付属のviolin.mqoを.xに変換して使用しています。<br /><a href="http://cdn21.atwikiimg.com/opengl/pub/png/violin.x">violin.x</a>は<a href="http://cdn21.atwikiimg.com/opengl/pub/png/violin.x">ここ</a>からダウンロードして下さい。<br /> 右クリックして名前を付けてリンク先を保存でダウンロードできます。</strong></p> <p><img alt="" src="http://cdn21.atwikiimg.com/opengl?cmd=upload&amp;act=open&amp;pageid=295&amp;file=off.png" /></p> <p>violin.png</p> <p><img alt="" src="http://www21.atwiki.jp/opengl?cmd=upload&amp;act=open&amp;pageid=295&amp;file=violin.png" /></p> <p> vertex.shader</p> <table cellspacing="1" cellpadding="1" width="600" border="1"><tbody><tr><td> <p>varying vec3 P;<br /> varying vec3 N;</p> <p>void main(void)<br /> {<br />   P = vec3(gl_ModelViewMatrix * gl_Vertex);<br />   N = normalize(gl_NormalMatrix * gl_Normal).xyz;<br />   gl_TexCoord[0] = gl_MultiTexCoord0;<br />   gl_Position = ftransform();<br /> }<br />  </p> </td> </tr></tbody></table><p>flagment.shader</p> <table cellspacing="1" cellpadding="1" width="600" border="1"><tbody><tr><td> <p>varying vec3 P;<br /> varying vec3 N;<br /> uniform sampler2D sampler;</p> <p>void main(void)<br /> {<br />   vec3 L = normalize(gl_LightSource[0].position.xyz - P);<br />   N = normalize(N);<br />  <br />   vec4 ambient = gl_FrontLightProduct[0].ambient;<br />   float dotNL = dot(N, L);//max(0.0, dot(N, L));<br />   vec4 diffuse = gl_FrontLightProduct[0].diffuse * max(0.0, dotNL);<br />  vec3 V = normalize(-P);<br />  vec3 H = normalize(L + V);<br />  float powNH = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);<br />  if(dotNL &lt;= 0.0) powNH = 0.0;<br />  vec4 specular = gl_FrontLightProduct[0].specular * powNH;<br />   //テクスチャの色<br />   vec4 texColor = texture2D(sampler, gl_TexCoord[0].st);<br />  //GL_MODULATEモード<br />  gl_FragColor = (ambient + diffuse) * texColor + specular;<br />  //任意の混合比<br /> // gl_FragColor = mix(ambient + diffuse, texColor, 0.5) + specular; <br /> }</p> </td> </tr></tbody></table><p>GLSL.h</p> <table cellspacing="1" cellpadding="1" width="600" border="1"><tbody><tr><td>#pragma once<br />  #include &lt;stdio.h&gt;<br />  <br /> //GLSLクラス<br />  class GLSL{<br />  public:<br />   GLuint ShaderProg;<br />   GLuint VertexShader, FragmentShader;<br />   void ReadShaderCompile(GLuint Shader, const char *File);//shader fileを読み込みコンパイルする<br />   void Link( GLuint Prog );//リンクする<br />   void InitGLSL(const char *VertexFile);//GLSLの初期化<br />   void InitGLSL(const char *VertexFile, const char *FragmentFile);//GLSLの初期化<br />   void ON();//シェーダー描画に切り替え<br />   void OFF();//シェーダー解除<br />   ~GLSL();<br />  };<br />  <br />  void GLSL::ReadShaderCompile(GLuint Shader, const char *File){<br />     FILE *fp;<br />     char *buf;<br />     GLsizei size, len;<br />     GLint compiled;<br />  <br />     fopen_s(&amp;fp,File, "rb");<br />     if(!fp) printf("ファイルを開くことができません %s\n", File);<br />  <br />     fseek(fp, 0, SEEK_END);<br />     size = ftell(fp);<br />  <br />    buf = (GLchar *)malloc(size);<br />     if (buf == NULL) {<br />       printf("メモリが確保できませんでした \n");<br />     }<br />  <br />     fseek(fp, 0, SEEK_SET);<br />     fread(buf, 1, size, fp);<br />     glShaderSource(Shader, 1, (const GLchar **)&amp;buf, &amp;size);<br />     free(buf);<br />     fclose(fp);<br />  <br />     glCompileShader(Shader);<br />     glGetShaderiv( Shader, GL_COMPILE_STATUS, &amp;compiled );<br />  <br />    if ( compiled == GL_FALSE )<br />     {<br />      printf( "コンパイルできませんでした!!: %s \n ", File);<br />      glGetProgramiv( Shader, GL_INFO_LOG_LENGTH, &amp;size );<br />      if ( size &gt; 0 )<br />      {<br />       buf = (char *)malloc(size);<br />       glGetShaderInfoLog( Shader, size, &amp;len, buf);<br />       printf(buf);<br />       free(buf);<br />      }<br />     }<br />   }<br />  <br />  void GLSL::Link( GLuint Prog ){<br />     GLsizei size, len;<br />     GLint linked;<br />     char *infoLog ;<br />  <br />    glLinkProgram( Prog );<br />  <br />    glGetProgramiv( Prog, GL_LINK_STATUS, &amp;linked );<br />  <br />    if ( linked == GL_FALSE ){<br />     printf("リンクできませんでした!! \n");<br />    <br />     glGetProgramiv( Prog, GL_INFO_LOG_LENGTH, &amp;size );<br />     if ( size &gt; 0 ){<br />      infoLog = (char *)malloc(size);<br />      glGetProgramInfoLog( Prog, size, &amp;len, infoLog );<br />      printf(infoLog);<br />      free(infoLog);<br />     }<br />    }<br />  }<br />  <br /> void GLSL::InitGLSL(const char *VertexFile){<br />     GLenum err = glewInit();<br />     if (err != GLEW_OK)<br />     {<br />      printf("Error: %s\n", glewGetErrorString(err));<br />     }<br />     printf("VENDOR= %s \n", glGetString(GL_VENDOR));<br />     printf("GPU= %s \n", glGetString(GL_RENDERER));<br />     printf("OpenGL= %s \n", glGetString(GL_VERSION));<br />     printf("GLSL= %s \n", glGetString(GL_SHADING_LANGUAGE_VERSION));<br />     VertexShader = glCreateShader(GL_VERTEX_SHADER);<br />     ReadShaderCompile(VertexShader, VertexFile);<br />     ShaderProg = glCreateProgram();<br />     glAttachShader(ShaderProg, VertexShader);<br />     glDeleteShader(VertexShader);<br />     Link(ShaderProg);<br />   }<br />  <br />  <br /> void GLSL::InitGLSL(const char *VertexFile, const char *FragmentFile){<br />     GLenum err = glewInit();<br />     if (err != GLEW_OK)<br />     {<br />      printf("Error: %s\n", glewGetErrorString(err));<br />     }<br />     printf("VENDOR= %s \n", glGetString(GL_VENDOR));<br />     printf("GPU= %s \n", glGetString(GL_RENDERER));<br />     printf("OpenGL= %s \n", glGetString(GL_VERSION));<br />     printf("GLSL= %s \n", glGetString(GL_SHADING_LANGUAGE_VERSION));<br />  <br />    VertexShader = glCreateShader(GL_VERTEX_SHADER);<br />     FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);<br />  <br />    ReadShaderCompile(VertexShader, VertexFile);<br />     ReadShaderCompile(FragmentShader, FragmentFile);<br />  <br />    ShaderProg = glCreateProgram();<br />  <br />     glAttachShader(ShaderProg, VertexShader);<br />     glAttachShader(ShaderProg, FragmentShader);<br />  <br />     glDeleteShader(VertexShader);<br />     glDeleteShader(FragmentShader);<br />     Link(ShaderProg);<br />   }<br />  <br /> void GLSL::ON(){<br />   glUseProgram(ShaderProg);<br />  }<br />  <br /> void GLSL::OFF(){<br />   glUseProgram(0);<br />  }<br />  <br /> GLSL::~GLSL(){<br />   glDeleteProgram(ShaderProg);<br />  }<br />  <br />  </td> </tr></tbody></table><p>PNG.h</p> <table cellspacing="1" cellpadding="1" width="600" border="1"><tbody><tr><td> #pragma once<br />  #include "lodepng.h"<br />  <br /> //テクスチャクラス<br />  class TEXTURE{<br />  protected:<br />   LodePNG_Decoder decoder;//デコーダ<br />   unsigned char* buffer;//バッファ<br />   size_t buffersize, imagesize;//サイズ<br />  public:<br />   TEXTURE();<br />   TEXTURE(const char* FileName);//コンストラクタ<br />   void LOAD_PNG(const char* FileName);//PNG読み込み<br />   unsigned char* image;//イメージポインタ<br />   unsigned int Width,Height;//画像サイズ<br />  };<br />  TEXTURE::TEXTURE(){<br />  }<br />  TEXTURE::TEXTURE(const char* FileName){<br />   LOAD_PNG(FileName);<br />  }<br />  void TEXTURE::LOAD_PNG(const char* FileName){<br />   LodePNG_Decoder_init(&amp;decoder);<br />   //ロード<br />   LodePNG_loadFile(&amp;buffer, &amp;buffersize, FileName);<br />   //デコード<br />   LodePNG_decode(&amp;decoder, &amp;image, &amp;imagesize, buffer, buffersize);<br />   //幅,高さ<br />   Width = decoder.infoPng.width;Height = decoder.infoPng.height;<br />  }<br />  </td> </tr></tbody></table><p>xfile.h</p> <table cellspacing="1" cellpadding="1" width="600" border="1"><tbody><tr><td> <p>#include "PNG.h"</p> <p>using namespace std;<br /> //3つのベクトル<br /> struct Vector3f{<br />  float x;<br />  float y;<br />  float z;<br /> }vec3d;<br /> Vector3f &amp; operator*(Vector3f &amp;v,float size){<br />  v.x *= size;<br />  v.y *= size;<br />  v.z *= size;<br />  return v;<br /> }<br /> //4つのベクトル<br /> struct Vector4f{<br />  float x;<br />  float y;<br />  float z;<br />  float w;<br /> }vec4d;<br /> //4つのカラー<br /> struct Color4{<br />  float r;<br />  float g;<br />  float b;<br />  float a;<br /> };<br /> //4つの反射<br /> struct Reflection4{<br />  Color4 diffuse;<br />  Color4 ambient;<br />  Color4 emission;<br />  Color4 specular;<br /> };<br /> //UV座標<br /> struct UV{<br />  float u;//u値<br />  float v;//v値<br /> }vec2d;<br /> //ポリゴンデータ<br /> struct Triangle{<br />  Vector3f TriVer;<br />  Vector3f TriNor;<br />  UV TriUV;<br /> }Tri;<br /> //ポリゴンデータ<br /> struct Quadrangle{<br />  Vector3f QuadVer;<br />  Vector3f QuadNor;<br />  UV QuadUV;<br /> }Quad;<br /> //マテリアル構造体<br /> struct MATERIAL{<br />  string MaterialName;//マテリアル名<br />  Reflection4 MaterialColor;//反射<br />  float Shininess;//shininess<br />  string TextureName;//テクスチャ名<br />  int TexNo;//テクスチャNO.<br />  vector &lt;Triangle&gt; Tridata;//三角面データ<br />  vector &lt;Quadrangle&gt; Quaddata;//四角面データ<br /> }mtl;<br /> //モデルクラス<br /> class MODEL{<br /> protected:<br />  vector &lt;MATERIAL&gt; Material;//マテリアル<br />  vector &lt;TEXTURE*&gt; TexData;//テクスチャデータ<br />  vector&lt;GLuint&gt; TexID;//テクスチャID<br />  GLuint TexID2;//代入用<br />  TEXTURE* tex;//代入用<br /> public:<br />  MODEL();<br />  MODEL(char* FileName,int size);//コンストラクタ<br />  bool XFILE_Load(char* FileName,int size);//ロード<br />  void Draw();<br /> };<br /> MODEL::MODEL(){<br /> }<br /> MODEL::MODEL(char* FileName,int size){<br />  XFILE_Load(FileName, size);<br /> }<br /> //描画<br /> void MODEL::Draw(){<br />  glEnableClientState(GL_VERTEX_ARRAY);<br />  glEnableClientState(GL_NORMAL_ARRAY);<br />  for(int i=0;i&lt;(signed)Material.size();i++){<br />   glPushMatrix();<br />   glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,(const GLfloat *)&amp;Material[i].MaterialColor.ambient);<br />   glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,(const GLfloat *)&amp;Material[i].MaterialColor.diffuse);<br />   glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,(const GLfloat *)&amp;Material[i].MaterialColor.specular);<br />   glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,Material[i].Shininess);<br />   if(Material[i].TexNo&gt;0){<br />    glEnableClientState(GL_TEXTURE_COORD_ARRAY);<br />    glEnable(GL_TEXTURE_2D);<br />    glBindTexture(GL_TEXTURE_2D, TexID[Material[i].TexNo-1]);<br />   }else{<br />    glDisable(GL_TEXTURE_2D);<br />    glDisableClientState(GL_TEXTURE_COORD_ARRAY);<br />   }<br />   if(Material[i].Tridata.size()&gt;1){<br />    glVertexPointer(3, GL_FLOAT,sizeof(Tri) , &amp;Material[i].Tridata[0].TriVer.x);<br />    glNormalPointer(GL_FLOAT,sizeof(Tri),&amp;Material[i].Tridata[0].TriNor.x);<br />    if(Material[i].TexNo&gt;0)glTexCoordPointer(2, GL_FLOAT, sizeof(Tri), &amp;Material[i].Tridata[0].TriUV.u);<br />    glDrawArrays(GL_TRIANGLES,0,Material[i].Tridata.size());<br />   }<br />   if(Material[i].Quaddata.size()&gt;1){<br />    glVertexPointer(3, GL_FLOAT,sizeof(Quad) , &amp;Material[i].Quaddata[0].QuadVer.x);<br />    glNormalPointer(GL_FLOAT,sizeof(Quad),&amp;Material[i].Quaddata[0].QuadNor.x);<br />    if(Material[i].TexNo&gt;0)glTexCoordPointer(2, GL_FLOAT, sizeof(Quad), &amp;Material[i].Quaddata[0].QuadUV.u);<br />    glDrawArrays(GL_QUADS,0,Material[i].Quaddata.size());<br />   }<br />   glPopMatrix();<br />  }<br />  glDisableClientState(GL_VERTEX_ARRAY);<br />  glDisableClientState(GL_NORMAL_ARRAY);<br />  glDisableClientState(GL_TEXTURE_COORD_ARRAY);<br />  glDisable(GL_TEXTURE_2D);<br /> }</p> <p>//Xファイル読み込み<br /> bool MODEL::XFILE_Load(char* FileName,int size){<br />  vector &lt;Vector3f&gt; Vertex;//頂点<br />  vector &lt;Vector3f&gt; Normal;//法線<br />  vector &lt;UV&gt; uv;//UV<br />  vector &lt;int&gt; VertexIndex;<br />  vector &lt;int&gt; NormalIndex;<br />  vector &lt;int&gt; MaterialIndex;<br />  vector &lt;int&gt; FaceIndex;</p> <p> char key[255];<br />  char buf[255];<br />  //Xファイルを開いて内容を読み込む<br />  FILE* fp=NULL;<br />  fopen_s(&amp;fp,FileName,"rt");<br />  <br />  int v1=0,v2=0,v3=0,v4=0;<br />  int Count=0;<br />  bool flag=false;<br />  string str="";</p> <p> //読み込み<br />  fseek(fp,SEEK_SET,0);<br />  while(!feof(fp))<br />  {<br />   //キーワード 読み込み<br />   ZeroMemory(key,sizeof(key));<br />   fscanf_s(fp,"%s ",key,sizeof(key));</p> <p>  //テンプレート読み飛ばし<br />   if(strcmp(key,"template")==0){<br />    while(strcmp(key,"}")){<br />     fscanf_s(fp,"%s ",key,sizeof(key));<br />    }<br />    continue;<br />   }</p> <p>  //マテリアル読み込み<br />   if(strcmp(key,"Material")==0)<br />   {<br />    if(flag)Material.push_back(mtl);<br />    flag=true;<br />    fgets(buf,sizeof(buf),fp);//直後の行にあると推定 改行する<br />    //ディフューズ<br />    fscanf_s(fp,"%f;%f;%f;%f;;",&amp;vec4d.x,&amp;vec4d.y,&amp;vec4d.z,&amp;vec4d.w);<br />    mtl.MaterialColor.diffuse=(const Color4 &amp;)vec4d;<br />    //SHININESS <br />    fscanf_s(fp,"%f;",&amp;mtl.Shininess);<br />    //スペキュラー<br />    fscanf_s(fp,"%f;%f;%f;;",&amp;vec4d.x,&amp;vec4d.y,&amp;vec4d.z);<br />    mtl.MaterialColor.specular=(const Color4 &amp;)vec4d;<br />    //エミッシブ<br />    fscanf_s(fp,"%f;%f;%f;;",&amp;vec4d.x,&amp;vec4d.y,&amp;vec4d.z);<br />    mtl.MaterialColor.ambient=(const Color4 &amp;)vec4d;</p> <p>   //テクスチャー<br />    fscanf_s(fp,"%s ",key,sizeof(key));<br />    if(strcmp(key,"TextureFilename")==0)<br />    {<br />     fgets(buf,sizeof(buf),fp);//直後の行にあると推定 改行する<br />     //map_Kd テクスチャー<br />     fscanf_s(fp,"%s",buf,255);<br />     mtl.TextureName=buf;<br />     str=mtl.TextureName;<br />     mtl.TextureName=str.substr(str.find_first_of('\"',0)+1,str.find_last_of('\"',255)-1);<br />      //テクスチャを作成<br />     TexData.push_back(tex);<br />     TexData[TexData.size()-1] = new TEXTURE(mtl.TextureName.c_str());;<br />     mtl.TexNo=TexData.size();<br />     TexID.push_back(TexID2);<br />     glGenTextures(1, (GLuint *)&amp;TexID[TexData.size()-1]);<br />     glBindTexture(GL_TEXTURE_2D, TexID[TexData.size()-1]);<br />     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);<br />     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);<br />     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);<br />     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);<br />  <br />     glEnable(GL_TEXTURE_2D);<br />     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,TexData[TexData.size()-1]-&gt;Width, TexData[TexData.size()-1]-&gt;Height,<br />      0,GL_RGBA, GL_UNSIGNED_BYTE, TexData[TexData.size()-1]-&gt;image);<br />     glDisable(GL_TEXTURE_2D);<br />    }<br />   }<br />   //頂点 読み込み<br />   if(strcmp(key,"Mesh")==0)<br />   {<br />    fgets(buf,sizeof(buf),fp);//データは2行下にあると推定 改行する<br />    fgets(buf,sizeof(buf),fp);<br />    Count=atoi(buf);<br />    for(int i=0;i&lt;Count ;i++)<br />    {<br />     fscanf_s(fp,"%f;%f;%f;,",&amp;vec3d.x,&amp;vec3d.y,&amp;vec3d.z);<br />     Vertex.push_back(vec3d*(float)size);<br />    }<br />    //頂点インデックス読み込み <br />    fgets(buf,sizeof(buf),fp);//データは2行下にあると推定 改行する<br />    fgets(buf,sizeof(buf),fp);<br />    while(strchr(buf,';')==NULL){fgets(buf,sizeof(buf),fp);}//空行対策<br />    Count=atoi(buf);  <br />    for(int i=0;i&lt;Count ;i++)<br />    {<br />     int dammy=0;<br />     fgets(buf,sizeof(buf),fp);<br />     str=buf;<br />     string::size_type first = str.find_first_not_of(" ");<br />     string::size_type index = str.find("3;");<br />     if(index-first==0){<br />      sscanf_s(buf,"%d;%d,%d,%d;,",&amp;dammy,&amp;v1,&amp;v2,&amp;v3);<br />      VertexIndex.push_back(v1);<br />      VertexIndex.push_back(v2);<br />      VertexIndex.push_back(v3);<br />     }<br />     if((index==-1)||(index-first&gt;1)){<br />      sscanf_s(buf,"%d;%d,%d,%d,%d;,",&amp;dammy,&amp;v1,&amp;v2,&amp;v3,&amp;v4);<br />      VertexIndex.push_back(v1);<br />      VertexIndex.push_back(v2);<br />      VertexIndex.push_back(v3);<br />      VertexIndex.push_back(v4);<br />     }<br />     FaceIndex.push_back(dammy);<br />    }<br />   }</p> <p>  //法線 読み込み<br />   if(strcmp(key,"MeshNormals")==0)<br />   {<br />    fgets(buf,sizeof(buf),fp);//データは2行下にあると推定 改行する<br />    fgets(buf,sizeof(buf),fp);<br />    Count=atoi(buf);<br />    for(int i=0;i&lt;Count ;i++)<br />    {<br />     fscanf_s(fp,"%f;%f;%f;,",&amp;vec3d.x,&amp;vec3d.y,&amp;vec3d.z);<br />     Normal.push_back(vec3d);<br />    }<br />    //法線インデックス読み込み <br />    fgets(buf,sizeof(buf),fp);//データは2行下にあると推定 改行する<br />    fgets(buf,sizeof(buf),fp);<br />    while(strchr(buf,';')==NULL){fgets(buf,sizeof(buf),fp);}//空行対策<br />    Count=atoi(buf);  <br />    for(int i=0;i&lt;Count ;i++)<br />    {<br />     int dammy=0;<br />     fgets(buf,sizeof(buf),fp);<br />     str=buf;<br />     string::size_type first = str.find_first_not_of(" ");<br />     string::size_type index = str.find("3;");<br />     if(index-first==0){<br />      sscanf_s(buf,"%d;%d,%d,%d;,",&amp;dammy,&amp;v1,&amp;v2,&amp;v3);<br />      NormalIndex.push_back(v1);<br />      NormalIndex.push_back(v2);<br />      NormalIndex.push_back(v3);<br />     }<br />     if((index==-1)||(index-first&gt;1)){<br />      sscanf_s(buf,"%d;%d,%d,%d,%d;,",&amp;dammy,&amp;v1,&amp;v2,&amp;v3,&amp;v4);<br />      NormalIndex.push_back(v1);<br />      NormalIndex.push_back(v2);<br />      NormalIndex.push_back(v3);<br />      NormalIndex.push_back(v4);<br />     }<br />    }<br />   }</p> <p>  //テクスチャー座標 読み込み<br />   if(strcmp(key,"MeshTextureCoords")==0)<br />   {<br />    fgets(buf,sizeof(buf),fp);//データは2行下にあると推定 改行する<br />    fgets(buf,sizeof(buf),fp);<br />    while(strchr(buf,';')==NULL){fgets(buf,sizeof(buf),fp);}//空行対策<br />    Count=atoi(buf);<br />    for(int i=0;i&lt;Count ;i++)<br />    {<br />     fscanf_s(fp,"%f;%f;,",&amp;vec2d.u,&amp;vec2d.v);<br />     uv.push_back(vec2d);<br />    }  <br />   }<br />   //マテリアルリスト<br />   if(strcmp(key,"MeshMaterialList")==0)<br />   {<br />    fgets(buf,sizeof(buf),fp);//空改行<br />    fgets(buf,sizeof(buf),fp);//マテリアル数<br />    fgets(buf,sizeof(buf),fp);//リスト要素数<br />    Count=atoi(buf);<br />    for(int i=0;i&lt;Count;i++)<br />    {<br />     fgets(buf,sizeof(buf),fp);<br />     int test=atoi(buf);<br />     MaterialIndex.push_back(test);<br />    }<br />   }<br />  }<br />  if(flag)Material.push_back(mtl);</p> <p> fclose(fp);</p> <p> Count=0;<br />  //マテリアル毎のデータを作成<br />  for(int i=0;i&lt;(signed)MaterialIndex.size();i++){<br />   if(FaceIndex[i]==3){<br />    for(int j=0;j&lt;3;j++){<br />     Tri.TriVer=Vertex[VertexIndex[Count+j]];<br />     Tri.TriNor=Normal[NormalIndex[Count+j]];<br />     Tri.TriUV=uv[VertexIndex[Count+j]];<br />     Material[MaterialIndex[i]].Tridata.push_back(Tri);<br />    }<br />    Count+=3;<br />   }else{<br />    for(int j=0;j&lt;4;j++){<br />     Quad.QuadVer=Vertex[VertexIndex[Count+j]];<br />     Quad.QuadNor=Normal[NormalIndex[Count+j]];<br />     Quad.QuadUV=uv[VertexIndex[Count+j]];<br />     Material[MaterialIndex[i]].Quaddata.push_back(Quad);<br />    }<br />    Count+=4;<br />   }<br />  }</p> <p> Vertex.clear();<br />  Normal.clear();<br />  uv.clear();<br />  VertexIndex.clear();<br />  NormalIndex.clear();<br />  MaterialIndex.clear();<br />  FaceIndex.clear();</p> <p> return true;<br /> }<br />  </p> </td> </tr></tbody></table><p>main.cpp</p> <table cellspacing="1" cellpadding="1" width="600" border="1"><tbody><tr><td> <p>#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")<br /> #pragma comment(lib, "glew32.lib")</p> <p>#include &lt;windows.h&gt;<br /> #include &lt;GL/glew.h&gt;<br /> #include "GLSL.h"<br /> #include &lt;math.h&gt;<br /> #include &lt;GL/freeglut/freeglut.h&gt;<br /> #include "xfile.h"</p> <p>float pos[] = { 0.0, 1.0, 0.0};<br /> float scale[][3] = { 1.0, 1.0, 1.0 };<br /> float angle[][3] = { 0.0, 0.0, 0.0};</p> <p>float lightPos[] = {-5.0, 5.0, 5.0, 1.0};<br /> float lightPosR[] = {5.0,-5.0, -5.0, 1.0};//光源位置(反射用)<br /> float shadowDiffuse[] =  {0.0,0.0,0.0,0.3};<br /> float shadowSpecular[] = {0.0,0.0,0.0,1.0};</p> <p>struct View{<br />   float pos[3];<br />   float cnt[3];<br />   float dist;<br />   float theta;<br />   float phi;<br />   float fovY;<br />   float nearZ;<br />   float farZ;<br /> };<br /> View view = {<br />  0.0, 0.0, 0.0,<br />  0.0, 1.0, 0.0,<br />  10.0, 30.0, 20.0,<br />  30.0, 1.0, 100.0<br /> };<br /> View view0 = view;</p> <p><br /> GLSL glsl;<br /> TEXTURE *texture[2];<br /> MODEL* model;<br /> #define PAI 3.141592f<br /> int width = 640;<br /> int height = 480;</p> <p>GLuint texName[2];<br /> int xStart, yStart;<br /> bool flagMouse = false;<br /> bool flagShadow = false;<br /> int objNo = 0;<br /> float ang = 0.0;<br /> float dang = 0.1;</p> <p>#define TEX_WIDTH  512<br /> #define TEX_HEIGHT 512</p> <p>void drawCube(float s){<br />  float p[8][3] = {<br />   {0.5*s,0.5*s,0.5*s}, {-0.5*s,0.5*s,0.5*s}, {-0.5*s,-0.5*s,0.5*s},<br />    {0.5*s,-0.5*s,0.5*s},{0.5*s,0.5*s,-0.5*s}, {-0.5*s,0.5*s,-0.5*s},<br />    {-0.5*s,-0.5*s,0-0.5*s}, {0.5*s,-0.5*s,-0.5*s}<br />  };</p> <p> glBegin(GL_QUADS);<br />   glNormal3f(0.0f,0.0f,1.0f); //z方向<br />   glVertex3fv(p[0]); glVertex3fv(p[1]);<br />   glVertex3fv(p[2]); glVertex3fv(p[3]);<br />   glNormal3f(1.0f,0.0f,0.0f); //x方向(正面)<br />   glVertex3fv(p[0]); glVertex3fv(p[3]);<br />   glVertex3fv(p[7]); glVertex3fv(p[4]);<br />   glNormal3f(0.0f,1.0f,0.0f); //y方向<br />   glVertex3fv(p[0]); glVertex3fv(p[4]);<br />   glVertex3fv(p[5]); glVertex3fv(p[1]);<br />    glNormal3f(-1.0f,0.0f,0.0f); //-x方向<br />   glVertex3fv(p[1]); glVertex3fv(p[5]);<br />   glVertex3fv(p[6]); glVertex3fv(p[2]);<br />   glNormal3f(0.0f,-1.0f,0.0f); //-y方向<br />   glVertex3fv(p[2]); glVertex3fv(p[6]);<br />   glVertex3fv(p[7]); glVertex3fv(p[3]);<br />   glNormal3f(0.0f,0.0f,-1.0f); //-z方向<br />   glVertex3fv(p[4]); glVertex3fv(p[7]);<br />   glVertex3fv(p[6]); glVertex3fv(p[5]);<br />  glEnd();<br /> }</p> <p>void drawTexCube(float size, int nRepeatS, int nRepeatT){<br />  float sz = 0.5 * size;<br />  float p[8][3] ={<br />   { sz, sz, sz}, {-sz, sz, sz}, {-sz,-sz, sz},<br />    { sz,-sz, sz}, { sz, sz,-sz}, {-sz, sz,-sz},<br />    {-sz,-sz,-sz}, { sz,-sz,-sz}<br />  };</p> <p> float s = (float)nRepeatS;<br />  float t = (float)nRepeatT;</p> <p> glEnable(GL_TEXTURE_2D);<br />   glBegin(GL_QUADS);<br />  //top(z軸が鉛直軸のときz方向)<br />  glNormal3f(0.0f,0.0f,1.0f);<br />  glTexCoord2f( s , 0.0); glVertex3fv(p[0]);<br />  glTexCoord2f( s ,  t ); glVertex3fv(p[1]);<br />  glTexCoord2f(0.0,  t ); glVertex3fv(p[2]);<br />  glTexCoord2f(0.0, 0.0); glVertex3fv(p[3]);<br />  //x方向(正面)<br />  glNormal3f(1.0f,0.0f,0.0f);<br />  glTexCoord2f( s ,  t ); glVertex3fv(p[0]);<br />  glTexCoord2f(0.0,  t ); glVertex3fv(p[3]);<br />  glTexCoord2f(0.0, 0.0); glVertex3fv(p[7]);<br />  glTexCoord2f( s , 0.0); glVertex3fv(p[4]);<br />  //y方向<br />  glNormal3f(0.0f,1.0f,0.0f);<br />  glTexCoord2f(0.0,  t ); glVertex3fv(p[0]);<br />  glTexCoord2f(0.0, 0.0); glVertex3fv(p[4]);<br />  glTexCoord2f( s , 0.0); glVertex3fv(p[5]);<br />  glTexCoord2f( s ,  t ); glVertex3fv(p[1]);<br />  //-x方向<br />  glNormal3f(-1.0f,0.0f,0.0f);<br />  glTexCoord2f(0.0,  t ); glVertex3fv(p[6]);<br />  glTexCoord2f(0.0, 0.0); glVertex3fv(p[2]);<br />  glTexCoord2f( s , 0.0); glVertex3fv(p[1]);<br />  glTexCoord2f( s ,  t ); glVertex3fv(p[5]);<br />  //-y方向<br />  glNormal3f(0.0f,-1.0f,0.0f);<br />  glTexCoord2f(0.0,  t ); glVertex3fv(p[2]);<br />  glTexCoord2f(0.0, 0.0); glVertex3fv(p[6]);<br />  glTexCoord2f( s , 0.0); glVertex3fv(p[7]);<br />  glTexCoord2f( s ,  t ); glVertex3fv(p[3]);<br />  //-z方向<br />  glNormal3f(0.0f,0.0f,-1.0f);<br />  glTexCoord2f(0.0, 0.0); glVertex3fv(p[6]);<br />  glTexCoord2f( s , 0.0); glVertex3fv(p[5]);<br />  glTexCoord2f( s ,  t ); glVertex3fv(p[4]);<br />  glTexCoord2f(0.0,  t ); glVertex3fv(p[7]);<br />   glEnd();<br />   glDisable(GL_TEXTURE_2D);<br /> }</p> <p>void TexCreate(int NO,char* FileName){<br />   glGenTextures(1, &amp;texName[NO]);<br />   texture[NO] = new TEXTURE(FileName);<br />   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);<br />   //テクスチャオブジェクトの作成<br />   glBindTexture(GL_TEXTURE_2D, texName[NO]);<br />   //テクスチャの指定<br />   glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,texture[NO]-&gt;Width,texture[NO]-&gt;Height,0,GL_RGBA,GL_UNSIGNED_BYTE,texture[NO]-&gt;image);<br />   //テクスチャの繰り返し方法の指定<br />   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);//GL_CLAMP);<br />   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);//GL_CLAMP);<br />   //テクスチャを拡大・縮小する方法の指定<br />   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//NEAREST);<br />   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//NEAREST);<br />   glBindTexture(GL_TEXTURE_2D, 0);<br /> }<br /> void resize(int w, int h){<br />   glViewport(0, 0, w, h);<br />   glMatrixMode(GL_PROJECTION);<br />   glLoadIdentity();<br />   gluPerspective(view.fovY, (double)w/(double)h, view.nearZ, view.farZ);<br />   glMatrixMode(GL_MODELVIEW);<br />   glLoadIdentity();<br />   width = w;<br />   height = h;<br /> }<br /> void setCamera(){<br />   float pp = PAI / 180.0f;<br />   view.pos[2] = view.cnt[2] + view.dist * cos(pp * view.theta) * cos(pp * view.phi);//z<br />   view.pos[0] = view.cnt[0] + view.dist * cos(pp * view.theta) * sin(pp * view.phi);//x<br />   view.pos[1] = view.cnt[1] + view.dist * sin(pp * view.theta);//y<br />  resize(width, height);</p> <p>}<br /> void setLight(){<br />   float lightAmbient0[] = {0.5, 0.5, 0.5, 1.0}; //環境光<br />   float lightDiffuse0[] = {1.0, 1.0, 1.0, 1.0}; //拡散光<br />   float lightSpecular0[] = {1.0, 1.0, 1.0, 1.0};//鏡面光<br />   glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient0);<br />   glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse0);<br />   glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular0);<br />   glLightfv(GL_LIGHT0, GL_POSITION, lightPos);</p> <p>  glEnable(GL_LIGHT0);<br />   glEnable(GL_LIGHTING);<br /> }<br /> void Init(void){<br />   glsl.InitGLSL("vertex.shader","flagment.shader");<br />   glClearColor(1.0f, 1.0f, 1.0f, 1.0f);<br />   setCamera();<br />   setLight();<br />   glEnable(GL_DEPTH_TEST);<br />   glEnable(GL_NORMALIZE);<br />   TexCreate(0,"marble.png");<br />   TexCreate(1,"marble.png");<br />   model = new MODEL("violin.x",2);<br /> }<br /> void idle(void){<br />   //再描画<br />   glutPostRedisplay();<br /> }</p> <p>void drawFloor(float widthX, float widthZ){<br />   float diffuse[] = { 0.8, 0.8, 0.8, 1.0};<br />   float ambient[] = { 0.2, 0.2, 0.2, 1.0};<br />   float specular[]= { 0.5, 0.5, 0.5, 1.0};</p> <p>  glMaterialfv(GL_FRONT,GL_AMBIENT,ambient);<br />   glMaterialfv(GL_FRONT,GL_SPECULAR,specular);<br />   glMaterialf(GL_FRONT,GL_SHININESS,10);<br />   glEnable(GL_TEXTURE_2D);<br />   glNormal3d(0.0, 1.0, 0.0);<br />   glPushMatrix();<br />   glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);<br />   glBegin(GL_QUADS);<br />   glTexCoord2f(0.0, 0.0);glVertex3d(widthX, 0.0, widthZ);<br />   glTexCoord2f( 1.0 , 0.0);glVertex3d(widthX, 0.0, -widthZ);<br />   glTexCoord2f( 1.0 ,  1.0 );glVertex3d(-widthX, 0.0, -widthZ);<br />   glTexCoord2f(0.0,  1.0 );glVertex3d(-widthX, 0.0, widthZ);<br />   glEnd();<br />   glPopMatrix();<br />   glDisable(GL_TEXTURE_2D);<br /> }<br /> void draw_obj(void){<br />   float ambient[] = { 0.3, 0.3, 0.3, 1.0};<br />   float diffuse[] = { 0.7, 0.7, 0.7, 1.0};<br />   float specular[]= { 0.5, 0.5, 0.5, 1.0};</p> <p> if(flagShadow)<br />   {<br />    glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,shadowDiffuse);<br />    glMaterialfv(GL_FRONT,GL_SPECULAR,shadowSpecular);<br />   }<br />   else<br />   { <br />    glMaterialfv(GL_FRONT,GL_AMBIENT,ambient);<br />    glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuse);<br />    glMaterialfv(GL_FRONT,GL_SPECULAR,specular);<br />    glMaterialf(GL_FRONT,GL_SHININESS,100);<br />   }</p> <p>  glPushMatrix();<br />   glTranslatef(pos[0], pos[1], pos[2]);<br />   glRotatef(angle[0][2], 0.0, 0.0, 1.0);//z軸回転<br />   glRotatef(angle[0][1]+ ang, 0.0, 1.0, 0.0);//y軸回転<br />   glRotatef(angle[0][0], 1.0, 0.0, 0.0);//x軸回転<br />   glScalef(scale[0][0], scale[0][1], scale[0][2]);<br />   //オブジェクト形状<br />   if(!flagShadow)<br />   {<br />   drawTexCube(1.5, 1, 1);<br />   }<br />   else<br />   {//影表示のときはTextureを付けない<br />   drawCube(1.5);<br />   }<br />   glPopMatrix();<br /> }<br /> void mouse(int button, int state, int x, int y){<br />   float pp = PAI / 180.0f;</p> <p>  if(button == GLUT_LEFT_BUTTON &amp;&amp; state == GLUT_DOWN){<br />    xStart = x; yStart = y;<br />    flagMouse = true;<br />   }else if(button == GLUT_RIGHT_BUTTON &amp;&amp; state == GLUT_DOWN){<br />    if(x &gt; width/4 &amp;&amp; x &lt; 3*width/4 &amp;&amp; y &gt; height/4 &amp;&amp; y &lt; 3*height/4){<br />    }else if(( x &lt; width/4 || x &gt; 3*width/4) &amp;&amp; (y &gt; height/4 &amp;&amp; y &lt; 3*height/4)){<br />     if(x &lt; width/4 ) view.phi -= 1.0;<br />     else view.phi += 1.0;<br />     view.cnt[2] = view.pos[2] - view.dist * cos(pp * view.phi) * cos(pp * view.theta);<br />     view.cnt[0] = view.pos[0] - view.dist * sin(pp * view.phi) * cos(pp * view.theta);<br />    }else if((x &gt; width/4 &amp;&amp; x &lt; 3*width/4) &amp;&amp; (y &lt; height/4 || y &gt; 3*height/4)){<br />     if( y &lt; height/4){<br />      view.theta += 1.0;<br />     }else{<br />      view.theta -= 1.0;<br />     }<br />     view.cnt[2] = view.pos[2] - view.dist * cos(pp * view.theta) * cos(pp * view.phi);<br />     view.cnt[0] = view.pos[0] - view.dist * cos(pp * view.theta) * sin(pp * view.phi);<br />     view.cnt[1] = view.pos[1] - view.dist * sin(pp * view.theta);<br />    }else if(x &lt; width/8 &amp;&amp; y &gt; 7*height/8) view.fovY -= 1.0;//zoom in<br />    else if(x &gt; 7*width/8 &amp;&amp; y &gt; 7*height/8) view.fovY += 1.0;//zoom out<br />   }else flagMouse = false;<br />   if(state == GLUT_DOWN) setCamera();<br /> }</p> <p>void motion(int x, int y){<br />   if(!flagMouse) return;<br />   if(cos(PAI * view.theta /180.0f) &gt;= 0.0f){<br />  view.phi -= 0.5f * (float)(x - xStart) ;//tumble<br />   }else{<br />  view.phi += 0.5f * (float)(x - xStart) ;//tumble<br />   }<br />   view.theta += 0.5f * (float)(y - yStart) ;//crane</p> <p>  setCamera();<br />   xStart = x;<br />   yStart = y;<br /> }</p> <p><br /> void CalcShadowMat(int ID, float* mat){<br />   float ex, ey, ez;//光源の方向<br />   float a, b, c, d;//床の面のパラメータ<br />   float s; //object中心から光源までの距離<br />   float x, y, z;</p> <p>  x = lightPos[0];<br />   y = lightPos[1];<br />   z = lightPos[2];</p> <p>  //光源の方向ベクトル<br />   s = sqrt(x * x + y * y + z * z);<br />   ex = x / s;<br />   ey = y / s;<br />   ez = z / s;</p> <p>  //フロアの方向ベクトル(y方向)<br />   a = 0.0f;<br />   b = 1.0f;<br />   c = 0.0f;<br />   d = -0.001f; //フロアと影の干渉を防ぐため<br />   mat[0] = b * ey + c * ez;<br />   mat[1] = -a * ey;<br />   mat[2] = -a * ez;<br />   mat[3] = 0.0f;<br />   mat[4] = -b * ex;<br />   mat[5] = a * ex + c * ez;<br />   mat[6] = -b * ez;<br />   mat[7] = 0.0f;<br />   mat[8] = -c * ex;<br />   mat[9] = -c * ey;<br />   mat[10] = a * ex + b * ey;<br />   mat[11] = 0.0f;<br />   mat[12] = -d * ex;<br />   mat[13] = -d * ey;<br />   mat[14] = -d * ez;<br />   mat[15] = a * ex + b * ey + c * ez;<br /> }</p> <p>void drawShadow(int objNo){<br />   float mat[16];</p> <p>  flagShadow = true;<br />   glEnable(GL_BLEND);<br />   glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);</p> <p>   glDepthMask(GL_FALSE);<br />   CalcShadowMat(objNo, mat);<br />   glPushMatrix();<br />    glMultMatrixf(mat);<br />    if(objNo == 0) draw_obj();</p> <p>  glDepthMask(GL_TRUE);<br />   glDisable(GL_BLEND);<br />   flagShadow = false;<br /> }</p> <p>void display(void){<br />   //textureの作成<br />   glClearColor( 1.0, 1.0, 1.0, 1.0 );<br />   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );<br />   glViewport( 0, 0, TEX_WIDTH, TEX_HEIGHT );<br />  <br />  glMatrixMode( GL_PROJECTION );<br />  glLoadIdentity();<br />   gluPerspective(view.fovY, (double)TEX_WIDTH/(double)TEX_HEIGHT, view.nearZ, view.farZ);<br />  glMatrixMode( GL_MODELVIEW );<br />  glLoadIdentity();<br />   if(cos(PAI * view.theta /180.0) &gt;= 0.0)<br />    gluLookAt(view.pos[0], view.pos[1], view.pos[2], view.cnt[0], view.cnt[1], view.cnt[2], 0.0, 1.0, 0.0);<br />   else<br />    gluLookAt(view.pos[0], view.pos[1], view.pos[2], view.cnt[0], view.cnt[1], view.cnt[2], 0.0, -1.0, 0.0);</p> <p>  glPushMatrix();<br />  glTranslatef(0.0, 1.0, 0.0);<br />  glRotatef(-90.0, 1.0, 0.0, 0.0);<br />  glRotatef(-90.0, 0.0, 0.0, 1.0);<br />  model-&gt;Draw();<br />  glPopMatrix();<br />  glBindTexture(GL_TEXTURE_2D, texName[1]);<br />  glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, TEX_WIDTH, TEX_HEIGHT);<br />   glBindTexture(GL_TEXTURE_2D, 0);</p> <p>  //通常のrendering<br />   resize(width, height);<br />   glClearColor(0.7, 0.7, 0.9, 1.0);<br />   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);<br />   glLoadIdentity();<br />   if(cos(PAI * view.theta /180.0) &gt;= 0.0)<br />    gluLookAt(view.pos[0], view.pos[1], view.pos[2], view.cnt[0], view.cnt[1], view.cnt[2], 0.0, 1.0, 0.0);<br />   else<br />    gluLookAt(view.pos[0], view.pos[1], view.pos[2], view.cnt[0], view.cnt[1], view.cnt[2], 0.0, -1.0, 0.0);</p> <p>  glLightfv(GL_LIGHT0, GL_POSITION, lightPos);</p> <p>  //描画<br />   glBindTexture(GL_TEXTURE_2D, texName[1]);<br />   glsl.ON();<br />   GLint samplerLoc = glGetUniformLocation(glsl.ShaderProg, "sampler");<br />   glUniform1i(samplerLoc, 0);//GL_TEXTURE0を適用<br />   draw_obj();<br />   glBindTexture(GL_TEXTURE_2D, texName[0]);<br />   drawFloor(10.0, 10.0);<br />   glsl.OFF();<br />   glBindTexture(GL_TEXTURE_2D, 0);</p> <p>  drawShadow(0);</p> <p>  glutSwapBuffers();<br /> }<br />  //タイマー<br />  void timer(int value){<br />   ang += dang;<br />   if(ang &gt;= 360.0f)ang = 0.0f;<br />   glutTimerFunc(10 , timer , 0);<br />  }<br />  int main(int argc, char *argv[]){<br />    glutInitWindowPosition(100, 100);<br />    glutInitWindowSize(TEX_WIDTH, TEX_HEIGHT);<br />    glutInit(&amp;argc, argv);<br />    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);<br />    glutCreateWindow("オフスクリーンレンダリング");<br />    glutDisplayFunc(display);<br />    glutIdleFunc(idle);<br />    glutMouseFunc(mouse);<br />    glutMotionFunc(motion);<br />    glutReshapeFunc(resize);<br />    glutTimerFunc(10 , timer , 0);<br />    Init();<br />    glutMainLoop();<br />    return 0;<br />  }</p> <p> </p> </td> </tr></tbody></table><p> </p> <p> </p> <p> </p> <p> </p> <p> </p>

表示オプション

横に並べて表示:
変化行の前後のみ表示: