続3DCGの理屈(cとWINAPIで書きます)のその2

記事
IT・テクノロジー
FlatShading(OBJ LOAD).png
006:OBJファイル読み込み
複数の行の文字列で表現されるOBJフォーマットですが、
その1つの行の先頭文字がvの場合、3次元座標を表します。
先頭文字がfの場合、頂点番号を表すので全体としてそれぞれの1つ1つのポリゴン単体の情報として表します。

つまり、例をあげると
v 0.005 0.25 0.125
v 0.5 0.21 0.05
v 0.025 0.1123 0.5
v 0.05 0.113 0.125
f 0,1,2,3
これで全体から見て1つ当たりの四角ポリゴンの内容です。

ちなみに、自分はShadeを使うこともあるので、
Shadeで円を描画して、閉じた線形状に変換して中央のY軸で回転させて
ドーナツの形にしたら、四角ポリゴンとしてOBJ形式でエクスポートしました。なので、blenderがエクスポートするOBJ形式を読み込むためには
どういう風に対応すれば良いかは分かりません。

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define WIDTH 320
#define HEIGHT 240
int min_[HEIGHT];
int max_[HEIGHT];
#define SCREENHEIGHT HEIGHT
#define SCALE 240.0f
int MAXVTX=0;//最大の頂点数
int MAXPOL=0;//最大のポリゴン数
int LastLine=0;
BITMAPINFO biInfo;
LPDWORD lpPixel;
struct TClipSize
{
 int width,height;
};
struct TClipBltInfo
{
 int sw,sh;
 int sx,sy;
 int dx,dy;
};
HBITMAP hBMP, hBMPOLD;
HDC hdcBMP;
HDC HdcGlobal;
char FileStr[10000][800];
int BMP[256][256];
int minX[HEIGHT];//最小バッファ
int maxX[HEIGHT];//最大バッファ
int minX2[HEIGHT];
int maxX2[HEIGHT];
int minU[HEIGHT];
int maxU[HEIGHT];
int minV[HEIGHT];
int maxV[HEIGHT];
int cmin[HEIGHT];
int cmax[HEIGHT];
void TRIANGLE(int x1,int y1,int x2,int y2,int x3,int y3,int col);//三角形を描画する関数
void LINE(int x1,int y1,int x2,int y2,int col);//線を描く関数
void PSET(int x,int y,int col);//点を打つ関数
void Projection2DAxisFrom3DAxis(HWND hwnd);
void SetXYZ(int num,double x,double y,double z);
void Init();
inline void TRIANGLE2(int x1,int y1,int x2,int y2,int x3,int y3,int c1,int c2,int c3);
BOOL ClipBltInfo(TClipSize *src,TClipSize *dest,TClipBltInfo *info);
typedef struct VTX{
 double x,y,z;
 int count;
 int R,G,B;
}VTX;
typedef struct XYZ{
    double x;
    double y;
    double z;
 int count;
}XYZ;
typedef struct XY{
    double x;
    double y;
}XY;
typedef struct COL{
 int r;
 int g;
 int b;
}COL;
#define RAD (3.14159265/180.0)
#define MAX_XYZ 5000
XYZ Pnt[MAX_XYZ];
XY Pnt2[MAX_XYZ];
XYZ vhMin[HEIGHT];
XYZ vhMax[HEIGHT];
int Poly[5000][4];
COL Cl[5000];
double vpx=1.0f,vpy=1.0f,vpz=-800.0f;
double D=424;
//XYZ vvv[5000];//全ての頂点の法線をクリアする
int vint[5000][3];
void Normalize(XYZ *a);//正規化関Calc
/*#ifdef _DEBUG
# define MyOutputDebugString( str, ... ) \
      { \
        char c[512]; \
        sprintf( c, str, __VA_ARGS__ ); \
        OutputDebugString( c ); \
      }
#else
//# define MyOutputDebugString( str, ... ) // 空実装
#endif
// CreateDIBSection32FromFile248.cpp
            */
BOOL ClipBltInfo(TClipSize *src,TClipSize *dest,TClipBltInfo *info)
{
 if((info->sw+info->dx)<=0) return FALSE;
 if((info->sh+info->dy)<=0) return FALSE;
 if(info->dx>=dest->width) return FALSE;
 if(info->dy>=dest->height) return FALSE;
 if((info->sx)>=src->width) return FALSE;
 if((info->sy)>= src->height) return FALSE;
 if((info->sx+info->sw)<0)return FALSE;
 if((info->sy+info->sh)<0) return FALSE;
 if((info->dx+info->sw)>=src->width) info->sw=(src->width-info->sx);
 if((info->dy+info->sh)>=src->height) info->sh=(src->height-info->sy);
 if(info->sx<0)
 {
  info->dx=info->dx+(-info->sx);
  info->sw=info->sw-(-info->sx);
  info->sx=0;
 }
 if(info->sy<0)
 {
  info->dy=info->dy+(-info->sy);
  info->sh=info->sh-(-info->sy);
  info->sy=0;
 }
 if(info->dx<0)
 {
  info->sx=info->sx+(-info->dx);
  info->sw=info->sw-(-info->dx);
  info->dx=0;
 }
 if(info->dy<0)
 {
  info->sy=info->sy+(-info->dy);
  info->sh=info->sh-(-info->dy);
  info->dy=0;
 }
 if((info->dx+info->sw)>dest->width) info->sw=dest->width-info->dx;
 if((info->dy+info->sh)>dest->height) info->sh=dest->height-info->dy;
 if(info->sw<1) return false;
 if(info->sh<1) return false;
 return true;
}
int CreateDIBSection32FromFile248(char *lpFileName,HBITMAP *lphBmp,LPDWORD *lppPixel,BITMAPINFO *lpBmpInfo);
void DeleteDIBSection32(HBITMAP *lphBmp);
void ScanUVEdge(double u1,double v1,double u2,double v2,int x1,int y1,int x2,int y2);
void readRGB(int u,int v,int *r,int *g,int *b);
int CreateDIBSection32FromFile248(char *lpFileName,HBITMAP *lphBmp,LPDWORD *lppPixel,BITMAPINFO *lpBmpInfo)
{
 HANDLE fh;
 DWORD dwFileSize,dwReadSize;
 LPBYTE lpbuf;
 LPBITMAPFILEHEADER lpbmpfh;
 LPBITMAPINFO lpbmpInfo;
 LPBYTE lpbmpPixel;
 LPRGBQUAD lpColorTable;
 int bitCount,iWidth,iHeight,iLength,x,y;
 fh=CreateFile(lpFileName,GENERIC_READ,0,NULL,
  OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 if(fh==INVALID_HANDLE_VALUE){
  MessageBox(NULL,"ファイルが開けません",lpFileName,MB_OK);
  return -1;
 }
 dwFileSize=GetFileSize(fh,NULL);
 lpbuf=(LPBYTE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwFileSize);
 ReadFile(fh,lpbuf,dwFileSize,&dwReadSize,NULL);
 CloseHandle(fh);
 lpbmpfh=(LPBITMAPFILEHEADER)lpbuf;
 lpbmpInfo=(LPBITMAPINFO)(lpbuf+sizeof(BITMAPFILEHEADER));
 bitCount=lpbmpInfo->bmiHeader.biBitCount;
 if(lpbmpfh->bfType!=('M'<<8)+'B' || (bitCount!=24 && bitCount!=8)){
  HeapFree(GetProcessHeap(),0,lpbuf);
     MessageBox(NULL,"24 or 8 ビットBMPファイルしか読み込めません",lpFileName,MB_OK);
  return -2;
 }
 lpbmpPixel=lpbuf + lpbmpfh->bfOffBits;
 iWidth=lpbmpInfo->bmiHeader.biWidth;
 iHeight=lpbmpInfo->bmiHeader.biHeight;
 if(iWidth*(bitCount/8)%4) iLength=iWidth*(bitCount/8)+(4-iWidth*(bitCount/8)%4);
 else iLength=iWidth*(bitCount/8);
 CopyMemory(lpBmpInfo,&lpbmpInfo->bmiHeader,sizeof(BITMAPINFOHEADER));
 lpBmpInfo->bmiHeader.biBitCount=32;
 *lphBmp=CreateDIBSection(NULL,lpBmpInfo,DIB_RGB_COLORS,(void**)lppPixel,NULL,0);
 switch(bitCount){
  case 24:
   for(y=0;y<iHeight;y++)
    for(x=0;x<iWidth;x++)
     CopyMemory(*lppPixel+x+y*iWidth,lpbmpPixel+x*3+y*iLength,3);
   break;
  case 8:
   lpColorTable=lpbmpInfo->bmiColors;
   for(y=0;y<iHeight;y++)
    for(x=0;x<iWidth;x++)
     CopyMemory(*lppPixel+x+y*iWidth,lpColorTable+lpbmpPixel[x+y*iLength],3);
   break;
 }
 HeapFree(GetProcessHeap(),0,lpbuf);
 return 0;
}
void DeleteDIBSection32(HBITMAP *lphBmp)
{
 if(*lphBmp!=NULL){
  DeleteObject(*lphBmp);
  *lphBmp=NULL;
 }
}
long int FPSCount=0;
void GF(int x1,int y1,int x2,int y2,int col)
{
 for(int y=y1;y<y2;y++)
 {
  for(int x=x1;x<x2;x++)
  {
   BMP[y][x]=col;
  }
 }
}
void DrawCheckMap()
{
 static int ix=0;
 int N=32;
 for(int i=0;i<256/N;i++)
 {
  if(i%2==0) ix^=1;
  for(int j=0;j<256/N;j++)
  {
   if(j%2==0) ix^=1;
   GF(i*N,j*N,i*N+(N-1),j*N+(N-1),RGB(ix*255,ix*255,ix*255));
  }
 }
 //BITMAP[i][j]=i;
}
void DrawTextureMapping(int x1,int y1,int x2,int y2,int x3,int y3)
{
 //UV座標の初期化を忘れずに
 //minX,maxXの初期化をわすれずに
 for(int i=0;i<HEIGHT;i++)
 {
  minX[i]= 100000;
  //minY[i]= 100000;
  minU[i]= 100000;
  minV[i]= 100000;
  maxX[i]=-100000;
  //maxY[i]=-100000;
  maxU[i]=-100000;
  maxV[i]=-100000;
 }
 DrawCheckMap();
 ScanUVEdge(0.0f,0.0f,1.0f,0.0f,x1,y1,x2,y2);
 ScanUVEdge(1.0f,0.0f,0.0f,1.0f,x2,y2,x3,y3);
 ScanUVEdge(0.0f,1.0f,0.0f,0.0f,x3,y3,x1,y1);
 //UとVの対応付けを行う関数
 int r,g,b;
 int u,v,x;
 for(int y=0;y<HEIGHT;y++)
 {
  for(double i=0.0f;i<1.0f;i+=0.001f)
  {
   u=(0*(1.0f-i)+1*i);
   v=(1*(1.0f-i)+0*i);
   x=(minX[y]*(1.0f-i)+maxX[y]*i);
   readRGB(u,v,&r,&g,&b);
   //DrawRGB(x,y,r,g,b);
   PSET(x,y,RGB(b,g,r));
  }
 }
}
void ScanUVEdge(double u1,double v1,double u2,double v2,int x1,int y1,int x2,int y2)
{
     for(double i=0;i<1.0;i+=0.001)
     {
          int x=(x1*(1-i)+x2*i);
          int y=(y1*(1-i)+y2*i);
          double u=(u1*(1-i)+u2*i);
          double v=(v1*(1-i)+v2*i);
          if(minX[y]>x) minX[y]=x;
          if(maxX[y]<x) maxX[y]=x;
          if(minU[y]>u) minU[y]=u;
          if(maxU[y]<u) maxU[y]=u;
          if(minV[y]>v) minV[y]=v;
          if(maxV[y]<v) maxV[y]=v;
     }
}
void readRGB(int u,int v,int *r,int *g,int *b)
{
      int u2=u*256;
      int v2=v*256;//BITMAPはSizeは256x256固定(^^;
      *r=BMP[u2][v2];
      *g=((BMP[u2][v2])>>8) & 0xFF;
      *b=((BMP[u2][v2])>>16) & 0xFF;
}
void DrawSquare(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,
    int c1,int c2,int c3,int c4)
{
 TRIANGLE2(x1,y1,x2,y2,x4,y4,c1,c2,c4);
 TRIANGLE2(x2,y2,x3,y3,x4,y4,c2,c3,c4);
}
inline void FASTScanEdge(int x1,int y1,int x2,int y2,int c1,int c2)
{
 int b1=(c1>>16) & 0xFF;
 int g1=(c1>>8) & 0xFF;
 int r1=c1 & 0xFF;
 int b2=(c2>>16) & 0xFF;
 int g2=(c2>>8) & 0xFF;
 int r2=c2 & 0xFF;
    for(int i=0;i<=1024;i++)
    {
        int ax=x1*((1<<10)-i)+x2*i>>10;
        int ay=y1*((1<<10)-i)+y2*i>>10;
        int k=((ay-(y1<<10)))/(y2-y1+1);
        if(ay<0 || ay>=HEIGHT) continue;
  if(minX[ay]>ax)
  {
   minX[ay]=ax;
   cmin[ay]=RGB( ((1<<10)-k)*b1+k*b2>>10,((1<<10)-k)*g1+k*g2>>10, ((1<<10)-k)*r1+k*r2>>10);
   PSET(ax,ay,cmin[ay]);
  }
  if(maxX[ay]<ax)
  {
   maxX[ay]=ax;
   cmax[ay]=RGB( ((1<<10)-k)*b1+k*b2>>10,
    ((1<<10)-k)*g1+k*g2>>10,
    ((1<<10)-k)*r1+k*r2>>10);
   PSET(ax,ay,cmax[ay]);
  }
    }
}
inline void FASTTRIANGLE(int x1,int y1,int x2,int y2,int x3,int y3,int c1,int c2,int c3)
{
 for(int i=0;i<HEIGHT;i++)
 {
  minX[i]=65536;
  maxX[i]=-65536;
  cmin[i]=RGB(0,0,0);
  cmax[i]=RGB(0,0,0);
 }
    FASTScanEdge(x1,y1,x2,y2,c1,c2);
    FASTScanEdge(x1,y1,x3,y3,c1,c3);
    FASTScanEdge(x2,y2,x3,y3,c2,c3);
    for(int y=0;y<HEIGHT;y++)
    {
        if(minX[y]==65536 && maxX[y]==-65536) continue;
        for(int x=minX[y];x<=maxX[y];x++)
  {
   int r1=cmin[y] & 0xFF;
   int g1=cmin[y]>>8 & 0xFF;
   int b1=cmin[y]>>16 & 0xFF;
   int r2=cmax[y] & 0xFF;
   int g2=cmax[y]>>8 & 0xFF;
   int b2=cmax[y]>>16 & 0xFF;
   int j=((x-minX[y])<<8)/(maxX[y]-minX[y]+1);
   int r=r1*((1<<8)-j)+(r2)*j>>8;
   int g=g1*((1<<8)-j)+(g2)*j>>8;
   int b=b1*((1<<8)-j)+(b2)*j>>8;
   int NewR=r;
   int NewG=g;
   int NewB=b;
   if(NewR<0) NewR=0; if(NewR>255) NewR=255;
   if(NewG<0) NewG=0; if(NewG>255) NewG=255;
   if(NewB<0) NewB=0; if(NewB>255) NewB=255;
            PSET(x,y,RGB(NewB,NewG,NewR));
  }
    }
}
void CalcFPS(HDC hdc)
{
 char str[100];
 static int FPS=0;
 static long int time=GetTickCount();
 //FPSCount++;
 if(GetTickCount()-time>1000)
 {
  time=GetTickCount();
  FPS=FPSCount;
  FPSCount=0;
 }else{
  FPSCount++;
 }
 sprintf(str,"FPS=%d",FPS);
 TextOut(hdc,0,0,str,strlen(str));
 //TextOut(hdc,0,90,"PRESS SPACE KEY!!",strlen("PRESS SPACE KEY!!"));
}
void SetColor(int num,int r,int g,int b)
{
 Cl[num].r=r;
 Cl[num].g=g;
 Cl[num].b=b;//そのポリゴンの色を指定する
}
XYZ CrossProduct(XYZ a,XYZ b)
{
    //23-32 31-13 12-21
    //YZ-ZY ZX-XZ XY-YX
    //aY*bZ-aZ*bY aZ*bX-aX*bZ aX*bY-aY*bX
    XYZ c;
    c.x=(a.y*b.z)-(a.z*b.y);
    c.x=(a.z*b.x)-(a.x*b.z);
    c.x=(a.x*b.y)-(a.y*b.x);
    return c;
}
double DotProduct(XYZ a,XYZ b)
{
 return a.x*b.x+a.y*b.y+a.z*b.z;
}
void Rotate(int X,int Y,int Z)
{
 int i;
 double cosSita=cos(Z*RAD);
 double sinSita=sin(Z*RAD);
    for(i=0;i<MAXVTX;i++)//Z軸、つまり2次元的な回転を行う(矢印キー右左で左右に回転する)
    {
        double x2=Pnt[i].x*cosSita-Pnt[i].y*sinSita;
        double y2=Pnt[i].x*sinSita+Pnt[i].y*cosSita;
        double z2=Pnt[i].z;
  //double x2_=vvv[i].x*cosSita-vvv[i].y*sinSita;
        //double y2_=vvv[i].x*sinSita+vvv[i].y*cosSita;
        //double z2_=vvv[i].z;
        Pnt[i].x=x2;
        Pnt[i].y=y2;
        Pnt[i].z=z2;
  //vvv[i].x=x2_;
        //vvv[i].y=y2_;
        //vvv[i].z=z2_;
    }
 double cosSita2=cos(X*RAD);
 double sinSita2=sin(X*RAD);
    for(i=0;i<MAXVTX;i++)//X軸、つまり奥か手前かに回転する(矢印キー↑↓で↑↓に回転する)
    {
        double y2=Pnt[i].y*cosSita2-Pnt[i].z*sinSita2;
        double z2=Pnt[i].y*sinSita2+Pnt[i].z*cosSita2;
        double x2=Pnt[i].x;
  //double y2_=vvv[i].y*cosSita2-vvv[i].z*sinSita2;
        //double z2_=vvv[i].y*sinSita2+vvv[i].z*cosSita2;
        //double x2_=vvv[i].x;
        Pnt[i].x=x2;
        Pnt[i].y=y2;
        Pnt[i].z=z2;
  //vvv[i].x=x2_;
        //vvv[i].y=y2_;
        //vvv[i].z=z2_;
    }
    for(i=0;i<MAXVTX;i++)//ここはY軸回転だが、今のところ使わない
    {
        double x3=Pnt[i].z*sin(Y*RAD)+Pnt[i].x*cos(Y*RAD);
        double z3=Pnt[i].z*cos(Y*RAD)-Pnt[i].x*sin(Y*RAD);
        double y3=Pnt[i].y;
  //double x3_=vvv[i].z*sin(Y*RAD)+vvv[i].x*cos(Y*RAD);
        //double z3_=vvv[i].z*cos(Y*RAD)-vvv[i].x*sin(Y*RAD);
        //double y3_=vvv[i].y;
        Pnt[i].x=x3;
        Pnt[i].y=y3;
        Pnt[i].z=z3;
  //vvv[i].x=x3_;
        //vvv[i].y=y3_;
        //vvv[i].z=z3_;
    }
}
void Projection2DAxisFrom3DAxis(HWND hwnd)
{
 HDC hdc = GetDC(hwnd);
    for(int i=0;i<MAXVTX;i++)
    {
        Pnt2[i].x=(Pnt[i].x*D)/(Pnt[i].z-vpz)+(WIDTH/2);
        Pnt2[i].y=-(Pnt[i].y*D)/(Pnt[i].z-vpz)+(HEIGHT/2);
        //PSET(Pnt2[i].x,Pnt2[i].y,0x00ffffff);
  //char str[100];
  //sprintf(str,"%d",i);
  //TextOut(hdc,Pnt2[i].x,Pnt2[i].y,str,strlen(str));
  //TextOut(hdc, 0, i*20, str, strlen(str));
    }
}
void SetPoly(int num,int n1,int n2,int n3,int n4)
{
 Poly[num][0]=n1;//頂点番号を指定
 Poly[num][1]=n2;
 Poly[num][2]=n3;
 Poly[num][3]=n4;
}
void SetPoly(int num,int n1,int n2,int n3)
{
 Poly[num][0]=n1;//頂点番号を指定
 Poly[num][1]=n2;
 Poly[num][2]=n3;
}
void SetPoly(int n1,int n2,int n3)
{
 static int num=0;
 Poly[num][0]=n1;//頂点番号を指定
 Poly[num][1]=n2;
 Poly[num][2]=n3;
 num++;
}
void SetXYZ(int num,double x,double y,double z)
{
    if(num<0 || num>=MAX_XYZ) return;
    Pnt[num].x=x;//頂点座標を指定
    Pnt[num].y=y;
    Pnt[num].z=z;
}
void Init()
{
    SetXYZ(0,-100.0,-100.0,-100.0);//8つの頂点を指定している
    SetXYZ(1, 100.0,-100.0,-100.0);
    SetXYZ(2, 100.0, 100.0,-100.0);
    SetXYZ(3,-100.0, 100.0,-100.0);
    SetXYZ(4,-100.0,-100.0, 100.0);
    SetXYZ(5, 100.0,-100.0, 100.0);
    SetXYZ(6, 100.0, 100.0, 100.0);
    SetXYZ(7,-100.0, 100.0, 100.0);
 SetPoly(0,1,2);
 SetPoly(2,3,0);
 SetPoly(3,4,0);
 SetPoly(3,7,4);
 SetPoly(7,6,5);
 SetPoly(7,5,4);
 SetPoly(6,2,1);
 SetPoly(6,1,5);
 SetPoly(5,1,0);
 SetPoly(0,4,5);
 SetPoly(6,7,3);
 SetPoly(6,3,2);
 MAXVTX = 7;
 SetColor(0,255,255,0);//それぞれのポリゴンの色を設定している
 SetColor(1,255,0,255);
 SetColor(2,0,255,255);
 SetColor(3,255,0,0);
 SetColor(4,0,0,255);
 SetColor(5,255,255,255);
 SetColor(6,255,120,255);
 SetColor(7,0,125,255);
 SetColor(8,255,0,255);
 SetColor(9,0,255,255);
 SetColor(10,255,255,0);
 SetColor(11,0,255,255);
 SetColor(12,255,0,255);
}
BOOL SetClientSize(HWND hWnd, int width, int height)
{
 RECT rw, rc;
 ::GetWindowRect(hWnd, &rw);
 ::GetClientRect(hWnd, &rc);
 int new_width = (rw.right - rw.left) - (rc.right - rc.left) + width;
 int new_height = (rw.bottom - rw.top) - (rc.bottom - rc.top) + height;
 return ::SetWindowPos(hWnd, NULL, 0, 0, new_width, new_height, SWP_NOMOVE | SWP_NOZORDER);
}
inline void PSET(int x, int y, int col)
{
 int R = (col >> 16) & 0xFF;
 int G = (col >> 8) & 0xFF;
 int B = col & 0xFF;
 int address;
 //点を打つ
 if (x >= 0 && y >= 0 && x < WIDTH && y < HEIGHT)
 {
  address = x + (y * WIDTH);
  lpPixel[address] = RGB(B,G,R);
 }
}
void LINE(int x1,int y1,int x2,int y2,int col)
{
    //線分を描画する
    for(int i=0;i<=256;i++)
    {
        int ax=x1*(256-i)+x2*i>>8;
        int ay=y1*(256-i)+y2*i>>8;
        PSET(ax,ay,col);
    }
}
inline void ClearScreen()
{
 //毎回ループの最初で画面を初期化する
 for(int i=0;i<HEIGHT;i++)
 {
  for(int j=0;j<WIDTH;j++)
  {
   PSET(j,i,0x00000000);
   //PSET(i,j,0x00000000);
  }
 }
}
inline void ScanEdge(int x1,int y1,int x2,int y2)
{
 //2次元的なスキャン
    for(int i=0;i<=1024;i++)
    {
        int ax=x1*((1<<10)-i)+x2*i>>10;
        int ay=y1*((1<<10)-i)+y2*i>>10;
        if(ay<0 || ay>=HEIGHT) continue;
  if(minX[ay]>ax) minX[ay]=ax;
  if(maxX[ay]<ax) maxX[ay]=ax;
    }
}
inline void ScanEdge(int x1,int y1,int x2,int y2,int c1,int c2)
{
 int r1=(c1>>16) & 0xFF;
 int g1=(c1>>8) & 0xFF;
 int b1=c1 & 0xFF;
 int r2=(c2>>16) & 0xFF;
 int g2=(c2>>8) & 0xFF;
 int b2=c2 & 0xFF;
    for(int i=0;i<1024;i++)//0.0~1.0を、0~1024に直す
    {
        int ax=(x1*(1024-i)+x2*i)>>10;//線形補間の固定小数点処理化(X成分
        int ay=(y1*(1024-i)+y2*i)>>10;//(固定小数点(Y成分
       // int k=(ay-y1)*100/(y2-y1);//0.0~1.0を0~256に直す
        if(ay<0 || ay>=HEIGHT) return;
  if(minX2[ay]>ax)//minなX(左側の線分)
  {
   minX2[ay]=ax;
   int b=((1024-i)*b1+i*b2)>>10;
   int g=((1024-i)*g1+i*g2)>>10;
   int r=((1024-i)*r1+i*r2)>>10;
   if(r<0) r=0; if(r>255) r=255;
   if(g<0) g=0; if(g>255) g=255;
   if(b<0) b=0; if(b>255) b=255;
   cmin[ay]=RGB(r,g,b);
   PSET(ax,ay,cmin[ay]);
  }
  if(maxX2[ay]<ax)//maxなX(右側の線分)
  {
   maxX2[ay]=ax;
   int b=((1024-i)*b1+i*b2)>>10;
   int g=((1024-i)*g1+i*g2)>>10;
   int r=((1024-i)*r1+i*r2)>>10;
   if(r<0) r=0; if(r>255) r=255;
   if(g<0) g=0; if(g>255) g=255;
   if(b<0) b=0; if(b>255) b=255;
   cmax[ay]=RGB(r,g,b);
   PSET(ax,ay,cmax[ay]);
  }
    }
}
void FillGraRect(int x1,int y1,int x2,int y2,
     int r1,int g1,int b1,
     int r2,int g2,int b2)
{
 for(int i=x1;i<x2;i++)
 {
  double d=(i-x1)/(double)(x2-x1);
  int r=r1*(1-d)+r2*d;
  int g=g1*(1-d)+g2*d;
  int b=b1*(1-d)+b2*d;
  LINE(i,y1,i,y2,RGB(b,g,r));
 }
}
inline void ScanEdge3(int x1,int y1,int x2,int y2,XYZ v1,XYZ v2)
{
    for(int i=0;i<1024;i++)//0.0~1.0を、0~1024に直す
    {
  //double j=(i<<10)/101.0;
        int ax=(x1*(1024-i)+x2*i)/1024;//線形補間の固定小数点処理化(X成分
        int ay=(y1*(1024-i)+y2*i)/1024;//(固定小数点(Y成分
       // int k=(ay-y1)*100/(y2-y1);//0.0~1.0を0~256に直す
        if(ay<0 || ay>=HEIGHT) return;
  if(minX2[ay]>ax)//minなX(左側の線分)
  {
   minX2[ay]=ax;
   vhMin[ay].x=((1024-i)*v1.x+i*v2.x)/1024;
   vhMin[ay].y=((1024-i)*v1.y+i*v2.y)/1024;
   vhMin[ay].z=((1024-i)*v1.z+i*v2.z)/1024;
   Normalize(&vhMin[ay]);
   //double InVx=(ax*D)/(vhMin[ay].z+vpz)+160;
   //double InVy=(ay*D)/(vhMin[ay].z+vpz)+120;
   //LINE(InVx,InVy,ax,ay,RGB(0,0,255));
   //cmin[ay]=RGB(r,g,b);
   //PSET(ax,ay,cmin[ay]);
  }
  if(maxX2[ay]<ax)//maxなX(右側の線分)
  {
   maxX2[ay]=ax;
   vhMax[ay].x=((1024-i)*v1.x+i*v2.x)/1024;
   vhMax[ay].y=((1024-i)*v1.y+i*v2.y)/1024;
   vhMax[ay].z=((1024-i)*v1.z+i*v2.z)/1024;
   Normalize(&vhMax[ay]);
   //cmax[ay]=RGB(r,g,b);
   //PSET(ax,ay,cmax[ay]);
  }
    }
}
inline void TRIANGLE3(int x1,int y1,int x2,int y2,int x3,int y3,XYZ v1,XYZ v2,XYZ v3,XYZ lig)
{
 for(int i=0;i<HEIGHT;i++)
 {
  minX2[i]=65816;
  maxX2[i]=-65816;
  cmin[i]=RGB(0,0,0);
  cmax[i]=RGB(0,0,0);
  vhMin[i].x=0.0f;
  vhMin[i].y=0.0f;
  vhMin[i].z=0.0f;
  vhMax[i].x=0.0f;
  vhMax[i].y=0.0f;
  vhMax[i].z=0.0f;
 }
    ScanEdge3(x1,y1,x2,y2,v1,v2);
    ScanEdge3(x2,y2,x3,y3,v2,v3);
    ScanEdge3(x3,y3,x1,y1,v3,v1);
    for(int y=0;y<HEIGHT;y++)
    {
        if(minX2[y]==65816 || maxX2[y]==-65816) continue;
        for(int x=minX2[y];x<=maxX2[y];x++)
  {
   int j=((x-minX2[y]))*1024/(maxX2[y]-minX2[y]+0.001);
   XYZ vv={0};
   vv.x=(vhMin[y].x*(1024-j)+(vhMax[y].x)*j)/1024;
   vv.y=(vhMin[y].y*(1024-j)+(vhMax[y].y)*j)/1024;
   vv.z=(vhMin[y].z*(1024-j)+(vhMax[y].z)*j)/1024;
   Normalize(&vv);
   /*
   double len=sqrt(vv.x*vv.x+vv.y*vv.y+vv.z*vv.z);
   vv.x/=len;
   vv.y/=len;
   vv.z/=len;
   */
   Normalize(&lig);
   double R=lig.x*vv.x+lig.y*vv.y+lig.z*vv.z;
   double G=lig.x*vv.x+lig.y*vv.y+lig.z*vv.z;
   double B=lig.x*vv.x+lig.y*vv.y+lig.z*vv.z;
   double R2=pow(R,55);
   double G2=pow(G,55);
   double B2=pow(B,55);
   PSET(x,y,RGB(B2*255,G2*255,R*255));
  }
    }
}
inline void TRIANGLE2(int x1,int y1,int x2,int y2,int x3,int y3,int c1,int c2,int c3)
{
 for(int i=0;i<HEIGHT;i++)
 {
  minX2[i]=65816;
  maxX2[i]=-65816;
  cmin[i]=RGB(0,0,0);
  cmax[i]=RGB(0,0,0);
 }
    ScanEdge(x1,y1,x2,y2,c1,c2);
    ScanEdge(x2,y2,x3,y3,c2,c3);
    ScanEdge(x3,y3,x1,y1,c3,c1);
    for(int y=0;y<HEIGHT;y++)
    {
        if(minX2[y]==65816 || maxX2[y]==-65816) continue;
        for(int x=minX2[y];x<=maxX2[y];x++)
  {
   int r1=cmin[y]>>16 & 0xFF;
   int g1=cmin[y]>>8 & 0xFF;
   int b1=cmin[y] & 0xFF;
   int r2=cmax[y]>>16 & 0xFF;
   int g2=cmax[y]>>8 & 0xFF;
   int b2=cmax[y] & 0xFF;
   int j=((x-minX2[y])<<8)/(maxX2[y]-minX2[y]+1);
   int r=(r1*(256-j)+(r2)*j)>>8;
   int g=(g1*(256-j)+(g2)*j)>>8;
   int b=(b1*(256-j)+(b2)*j)>>8;
   int NewR=r;
   int NewG=g;
   int NewB=b;
   if(NewR<0) NewR=0; if(NewR>255) NewR=255;
   if(NewG<0) NewG=0; if(NewG>255) NewG=255;
   if(NewB<0) NewB=0; if(NewB>255) NewB=255;
            PSET(x,y,RGB(NewR,NewG,NewB));
  }
    }
}
inline void TRIANGLE(int x1,int y1,int x2,int y2,int x3,int y3,int col)
{
 for(int i=0;i<HEIGHT;i++)
 {
  minX[i]=65536;
  maxX[i]=-65536;
 }
    ScanEdge(x1,y1,x2,y2);
    ScanEdge(x1,y1,x3,y3);
    ScanEdge(x2,y2,x3,y3);
    for(int y=0;y<HEIGHT;y++)
    {
        if(minX[y]==65536 || maxX[y]==-65536) continue;
        for(int x=minX[y];x<=maxX[y];x++)
  {
            PSET(x,y,col);
  }
    }
}
void Normalize(XYZ *a)//正規化関Calc
{
   double len=sqrt(a->x*a->x+a->y*a->y+a->z*a->z);
   a->x/=len;
   a->y/=len;
   a->z/=len;
}
double CalcSpecular(XYZ eye,XYZ light,XYZ housen,XYZ n,XYZ buttai)
{
   XYZ RLine;
   XYZ RLight;
   XYZ Ref;
   RLine.x=eye.x-buttai.x;
   RLine.y=eye.y-buttai.y;
   RLine.z=eye.z-buttai.z;//逆視線ベクトルの計算
   Normalize(&RLine);//正規化
   RLight.x=light.x-buttai.x;
   RLight.y=light.y-buttai.y;
   RLight.z=light.z-buttai.z;//逆光線ベクトルの計算
   Normalize(&RLight);//正規化
   double ll=n.x*RLight.x+n.y*RLight.y+n.z*RLight.z;
   Ref.x=ll*2+n.x*RLight.x;
   Ref.x=ll*2+n.y*RLight.y;
   Ref.x=ll*2+n.z*RLight.z;//反射光線ベクトルの計算
   Normalize(&Ref);//正規化
   double a=Ref.x*RLine.x+Ref.y*RLine.y+Ref.z*RLine.z;//反射光線ベクトルと逆視線ベクトルの内積
   return pow(a,30);
}
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInst;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow){
 HWND hwMain;
 MSG msg;
 WNDCLASS wndclass;
 hInst = hInstance;
 wndclass.style = CS_HREDRAW | CS_VREDRAW;
 wndclass.lpfnWndProc = WndProc;
 wndclass.cbClsExtra = 0;
 wndclass.cbWndExtra = 0;
 wndclass.hInstance = hInstance;
 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
 wndclass.lpszMenuName = NULL;
 wndclass.lpszClassName = "CWindow";
 RegisterClass(&wndclass);
 hwMain = CreateWindow("CWindow", "Phong Shading(is Testing)",
          WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
          WIDTH*2+22,HEIGHT*2+36+6, NULL, NULL, hInstance, NULL);
    SetClientSize(hwMain,320*2,240*2);//ウィンドウサイズ丁度良いサイズに調整してくれる
 /* ウインドウを表示 */
 ShowWindow(hwMain, iCmdShow);
 UpdateWindow(hwMain);
 /* メッセージループ */
 while(GetMessage(&msg, NULL, 0, 0)) {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
 return msg.wParam;
}
inline void LINE2COL(int x1,int y1,int x2,int y2,int COL,int COL2)
{
 //線を描くのと左か右かを判断する関数
 int NewX,NewY;
 for(int j=0;j<256;j++)
 {
  NewX=x1*(256-j)+x2*j>>8;
  NewY=y1*(256-j)+y2*j>>8;
  int R1,R2,G1,G2,B1,B2;
  R1=(COL>>16) & 0xFF;
  G1=(COL>>8) & 0xFF;
  B1=(COL) & 0xFF;
  R2=(COL2>>16) & 0xFF;
  G2=(COL2>>8) & 0xFF;
  B2=(COL2) & 0xFF;
  int R=R1*(256-j)+R2*j>>8;
  int G=G1*(256-j)+G2*j>>8;
  int B=B1*(256-j)+B2*j>>8;
  PSET(NewX,NewY,RGB(R,G,B));
  if(min_[(int)NewY]>NewX){
   min_[(int)NewY]=NewX;
   cmin[(int)NewY]=RGB(R,G,B);
  }
  if(max_[(int)NewY]<NewX){
   max_[(int)NewY]=NewX;
   cmax[(int)NewY]=RGB(R,G,B);
  }
 }
}
int min_Y(int y1,int y2,int y3)
{
 if(y1<y2 && y1<y3) return y1;
 if(y2<y1 && y2<y3) return y2;
 if(y3<y1 && y3<y2) return y3;
}
int max_Y(int y1,int y2,int y3)
{
 if(y1>y2 && y1>y3) return y1;
 if(y2>y1 && y2>y3) return y2;
 if(y3>y1 && y3>y2) return y3;
}
inline void GouraudShade(int x1,int y1,int x2,int y2,int x3,int y3,int C1,int C2,int C3)
{
 //入れ忘れ(笑)
 for(int i=0;i<SCREENHEIGHT;i++)
 {
  min_[i]=65816;
  max_[i]=-65816;
  cmin[i]=RGB(0,0,0);
  cmax[i]=RGB(0,0,0);
 }
 //LINE2COL(x1,y1,x2,y2,C1,C2);
 //LINE2COL(x2,y2,x3,y3,C2,C3);
 //LINE2COL(x1,y1,x3,y3,C1,C3);
 ScanEdge(x1,y1,x2,y2,C1,C2);
 ScanEdge(x2,y2,x3,y3,C2,C3);
 ScanEdge(x3,y3,x1,y1,C3,C1);
 for(int Y=0;Y<HEIGHT;Y++)
 {
  if(min_[Y]==65816 || max_[Y]==-65816) continue;
  int R1=(cmin[Y]>>16) & 0xFF;
  int G1=(cmin[Y]>>8) & 0xFF;
  int B1=(cmin[Y]) & 0xFF;
  int R2=(cmax[Y]>>16) & 0xFF;
  int G2=(cmax[Y]>>8) & 0xFF;
  int B2=(cmax[Y]) & 0xFF;
  LINE2COL(min_[Y],Y,max_[Y],Y,RGB(R1,G1,B1),RGB(R2,G2,B2));
 }
}
void LoadOBJFile(char filename[10000],HWND hwnd)
{
 static int flag=0;
 FILE *fp;
 fp=fopen(filename,"r");
 if(fp==NULL)
 {
  MessageBox(NULL,"ファイルがありません。","OK?",MB_OK);
  SelectObject(hdcBMP, hBMPOLD);
  DeleteObject(hdcBMP);
  DeleteObject(hBMP);
  PostQuitMessage(0);
  return;
 }
 int i=0;
 int j=0;
 while(fgets(FileStr[i],50,fp)!=NULL)
 {
  j=0;
  //以下の内容が通用しないのでテキストエディタ(最悪Windowsのメモ帳でも可)
  //で空白を,(カンマ)に変換する必要がある、
  //通用した、改行の処理を忘れていただけのようだ。これで、objファイルは大丈夫のようだ
  while(FileStr[i][j])
  {
   if(FileStr[i][j]==' ') FileStr[i][j]=',';
   ++j;
   if(FileStr[i][j]=='\n') ++i;
  }
 }
 LastLine=i;//最後の行数を保存する
 char opecode[10000]={0};
 double XF,YF,ZF;
 int TriNum1,TriNum2,TriNum3,TriNum4;
 int k=0;
 for(i=0;i<LastLine;i++)
 {
   opecode[0]=FileStr[i][0];
   //CameraPos.D=535.0f;
   //CameraPos.Z=-810.0f;
   //PSET(400,300,GetColor(0,0,255));
   if(opecode[0]=='v')
   {
    sscanf(FileStr[i],"%c,%lf,%lf,%lf",
    opecode,&XF,&YF,&ZF);
    SetXYZ(k,XF*SCALE,YF*SCALE,ZF*SCALE);
    Projection2DAxisFrom3DAxis(hwnd);
    //i=0;
    ++k;
    MAXVTX=k;
   }
   if(opecode[0]=='f')
   {
    sscanf(FileStr[i],"%c,%d,%d,%d,%d",
    opecode,&TriNum1,&TriNum2,&TriNum3,&TriNum4);
    if(flag==0)
    {
     j=0;
     flag=1;
    }
    SetPoly(j,(int)TriNum1-1,(int)TriNum2-1,(int)TriNum3-1,(int)TriNum4-1);
    Projection2DAxisFrom3DAxis(hwnd);
    ++j;
    MAXPOL=j;
   }
 }
}
XYZ CalcCross(XYZ a,XYZ b,XYZ c)
{
 XYZ d={0.0f};
 XYZ a2,b2;
   a2.x=a.x-b.x;
   a2.y=a.y-b.y;
   a2.z=a.z-b.z;
   b2.x=a.x-c.x;
   b2.y=a.y-c.y;
   b2.z=a.z-c.z;
   Normalize(&a2);
   //double len=sqrt(a2.x*a2.x+a2.y*a2.y+a2.z*a2.z+0.1);
   //a2.x/=len;
   //a2.y/=len;
   //a2.z/=len;
   Normalize(&b2);
   //double len2=sqrt(b2.x*b2.x+b2.y*b2.y+b2.z*b2.z+0.1);
   //b2.x/=len2;
   //b2.y/=len2;
   //b2.z/=len2;
            //23-32 31-13 12-21
            //aY*bZ-aZ*bY aZ*bX-aX*bZ aX*bY-aY*bX
   d.x=a2.y*b2.z-a2.z*b2.y;
   d.y=a2.z*b2.x-a2.x*b2.z;
   d.z=a2.x*b2.y-a2.y*b2.x;
  return d;
}
double CalcDotProduct(XYZ a, XYZ b)
{
 return a.x * b.x + a.y * b.y + a.z * b.z;
}
int JisakuRGB(int R, int G, int B)
{
 if (R > 255) R = 255;
 if (G > 255) G = 255;
 if (B > 255) B = 255;
 if (R < 0) R = 0;
 if (G < 0) G = 0;
 if (B < 0) B = 0;
 return R << 16 | G << 8 << B;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
    HDC hdc;
    PAINTSTRUCT ps;
 static int DrawMode = 1;
 static int prevSpace = 0;
    switch (iMsg) {
    case WM_TIMER:
        {
            if(GetAsyncKeyState(VK_ESCAPE)<0)
                SendMessage(hwnd,WM_DESTROY,NULL,NULL);
            double X=0.0f;
            double Y=0.0f;
            double Z=0.0f;
            //Z+=0.1f;
            //Y+=0.1f;
            if(GetAsyncKeyState(VK_RIGHT)<0) Y=-2.5f;
            else if(GetAsyncKeyState(VK_LEFT)<0) Y=2.5f;
            else Y=0.0f;
            if(GetAsyncKeyState(VK_DOWN)<0) X=-2.5f;
            else if(GetAsyncKeyState(VK_UP)<0) X=2.5f;
            else X=0.0f;
   if (GetAsyncKeyState(VK_SPACE) < 0 && !prevSpace)
    DrawMode = (DrawMode + 1) & 3;
   prevSpace = GetAsyncKeyState(VK_SPACE) < 0;
            Rotate(X,Y,0);
            static int X1=0,X2=0;
            int n=8;
            InvalidateRect(hwnd,NULL,NULL);
        }
        return 0;
    case WM_CREATE:
       //MyOutputDebugString("起動しました。");
        //Init();//3次元座標を代入
 // SetXYZ(0,-100,-100,0);
 // SetXYZ(1,-100,100,0);
 // SetXYZ(2,100,100,0);
 // SetXYZ(3,100,-100,0);
 /*SetXYZ(0,-100.0,-100.0,-100.0);//8つの頂点を指定している
    SetXYZ(1, 100.0,-100.0,-100.0);
    SetXYZ(2, 100.0, 100.0,-100.0);
    SetXYZ(3,-100.0, 100.0,-100.0);
  SetPoly( 0,1,2);
  SetPoly(2,3,0);
*/
  //Projection2DAxisFrom3DAxis(hwnd);
   /*
   0 3
   ********
   *++++++*
   *++++++*
   *++++++*
   ********
   1 2
   */
        //LoadOBJFile("./womanbody.obj",hwnd);
        //LoadOBJFile("./heimen.obj",hwnd);//cube.obj
        //LoadOBJFile("./DO-NATSU.obj",hwnd);
  LoadOBJFile("./do-natsu.obj",hwnd);
        SetTimer(hwnd,100,1000/60,NULL);
        /* BITMAPINFOをゼロクリア */
        ZeroMemory(&biInfo, sizeof(BITMAPINFO));
        /* BITMAPINFO設定 */
        biInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        biInfo.bmiHeader.biWidth = WIDTH;
        biInfo.bmiHeader.biHeight = -HEIGHT;
        biInfo.bmiHeader.biPlanes = 1;
        biInfo.bmiHeader.biBitCount = 32;
        biInfo.bmiHeader.biCompression = BI_RGB;
        /* ウインドウのDCを取得 */
        hdc = GetDC(hwnd);
        /* biInfoの形式でDIBSectionを作成 */
        hBMP =CreateDIBSection(hdc, &biInfo, DIB_RGB_COLORS, (LPVOID*)(&lpPixel), NULL, 0);
        /* DIBSection用のメモリDCを作成 */
        hdcBMP = CreateCompatibleDC(hdc);
        /* メモリDCにDIBSectionを選択 */
        hBMPOLD = (HBITMAP)SelectObject(hdcBMP, hBMP);
        /* 不要になったウインドウのDCを解放 */
        ReleaseDC(hwnd, hdc);
        return 0;
    case WM_PAINT:
        {
  int i;
        hdc = BeginPaint(hwnd, &ps);
        ClearScreen();//画面を消す
        //PSET(320,240,0x00ff0000);//点を打つ
        //LINE(320,240,640,380,0x00ff0000);
  TRIANGLE2(80,50,10,140,260,80,RGB(255,0,0),RGB(0,255,0),RGB(0,0,255));
        Projection2DAxisFrom3DAxis(hwnd);//透視投影
  //PSET(160, 120, 0x00ff0000);
        //PSET(320,240,0x00FFFFFF);
        XYZ vvv[1000];//全ての頂点の法線をクリアする
        for(i=0;i<MAXVTX;i++)
        {
            vvv[i].x=0.0f;//Clear
            vvv[i].y=0.0f;//Clear
            vvv[i].z=0.0f;//Clear
   vvv[i].count =0;
        }
        XYZ a[1000];
        XYZ b[1000];
        //XYZ n3;
        //頂点ベクトルは求まった(はず...)から、頂点カラーを面にある全ての頂点で求める
  //XYZ vpx=200,vpy=-120,vpz=100;
  for (i = 0; i < MAXVTX; i++)
  {
   int i1 = Poly[i][0];
   int i2 = Poly[i][1];
   int i3 = Poly[i][2];
   int i4 = Poly[i][3];
   XYZ n = CalcCross(Pnt[i1], Pnt[i2], Pnt[i3]);
   //外積を行った
   Normalize(&n);
   //正規化を行った
   XYZ n2 = CalcCross(Pnt[i3], Pnt[i4], Pnt[i2]);
   //外積を行った
   Normalize(&n2);
   //正規化を行った
   vvv[i1].x += n.x;
   vvv[i1].y += n.y;
   vvv[i1].z += n.z;
   vvv[i2].x += n.x;
   vvv[i2].y += n.y;
   vvv[i2].z += n.z;
   vvv[i3].x += n.x;
   vvv[i3].y += n.y;
   vvv[i3].z += n.z;
   vvv[i4].x += n2.x;
   vvv[i4].y += n2.y;
   vvv[i4].z += n2.z;
  }
  for (i = 0; i < MAXVTX; i++)
  {
   Normalize(&vvv[i]);
   //vvv[i].x/=vvv[i].count ;
   //vvv[i].y/=vvv[i].count ;
   //vvv[i].z/=vvv[i].count ;
  }
        //XYZ vpx=200,vpy=-120,vpz=100;
        for(i=0;i<MAXVTX;i+=1)
        {
            int i1=Poly[i][0];
            int i2=Poly[i][1];
            int i3=Poly[i][2];
   int i4 = Poly[i][3];
            XYZ n=CalcCross(Pnt[i1],Pnt[i2],Pnt[i3]);
   Normalize(&n);
            XYZ light={0,0,-5};
            double lenlight=sqrt((double)light.x*light.x+light.y*light.y+light.z*light.z+0.1);
            light.x/=lenlight;
            light.y/=lenlight;
            light.z/=lenlight;
   double spe1 = vvv[i1].x * light.x + vvv[i1].y * light.y + vvv[i1].z * light.z;
   double spe2 = vvv[i2].x * light.x + vvv[i2].y * light.y + vvv[i2].z * light.z;
   double spe3 = vvv[i3].x * light.x + vvv[i3].y * light.y + vvv[i3].z * light.z;
   double spe4 = vvv[i4].x * light.x + vvv[i4].y * light.y + vvv[i4].z * light.z;
            double ViewCos;
   //-------------------------------------------------------------------------
            double v7=ViewCos=(light.x*n.x+light.y*n.y+light.z*n.z);
   double p=pow(ViewCos, 50);
   if (p > 255) p = 255;
   //-------------------------------------------------------------------------
            //視線ベクトルと面ごとの法線ベクトルの内積
   //ViewCos<0
   if (ViewCos > 0)
   {
    if (DrawMode) {
     TRIANGLE(Pnt2[Poly[i][1]].x, Pnt2[Poly[i][1]].y,
      Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      RGB(v7 * 255, v7 * 255, v7 * 255)
      //vvv[i1],vvv[i2],vvv[i3],light
     );
     TRIANGLE(Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      Pnt2[Poly[i][3]].x, Pnt2[Poly[i][3]].y,
      RGB(v7 * 255, v7 * 255, v7 * 255)
      //JisakuRGB(p * 255 * 50 + 30, p * 201 + 1 + 30, p * 201 + 1 + 30)
      //vvv[i1],vvv[i2],vvv[i3],light
     );
    }
    /*else if (DrawMode == 2)
    {
     //TRIANGLE(Pnt2[Poly[i][1]].x, Pnt2[Poly[i][1]].y,
     // Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
     // Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
     // //vvv[i1],vvv[i2],vvv[i3],light
     //);
     //TRIANGLE(Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
     // Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
     // Pnt2[Poly[i][3]].x, Pnt2[Poly[i][3]].y,
     // RGB(v7 * 255, v7 * 255, v7 * 255)
      double p = pow(ViewCos, 30);
     double pgb = ViewCos * 1.0f;
     //double R2=pow(spe1*1,55);
     TRIANGLE2(Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      Pnt2[Poly[i][1]].x, Pnt2[Poly[i][1]].y,
      Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      //RGB(ViewCos*255,ViewCos*255,ViewCos*255)
      RGB(spe1*255, spe1 * 255, spe1 * 255),
      RGB(spe2 *255, spe2 * 255, spe2 * 255),
      RGB(spe3*255, spe3 * 255, spe3 * 255)
     );
     TRIANGLE2(Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      Pnt2[Poly[i][3]].x, Pnt2[Poly[i][3]].y,
      Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      //RGB(ViewCos*255,ViewCos*255,ViewCos*255)
      RGB(spe3 * 255, spe3 * 255, spe3 * 255),
      RGB(spe4 * 255, spe4 * 255, spe4 * 255),
      RGB(spe1 * 255, spe1 * 255, spe1 * 255)
     );
     //TRIANGLE(Pnt2[0].x, Pnt2[0].y, Pnt2[1].x, Pnt2[1].y, Pnt2[17].x, Pnt2[17].y, RGB(0, 0, 255));
    }*/
   }
        }
        //反時計回りの座標軸
        //三角形を表示する
            //DrawTextureMapping(240,0,0,120,240,0);
            //FillGraRect(0,0,320,20,255,0,0,0,255,0);
  /*
  TClipSize a5,b5;
  a5.width =320;
  a5.height=240;
  b5.width =320;
  b5.height =240;
  TClipBltInfo c;
   c.dx=0;
   c.dy=0;
   c.sh=240;
   c.sw=320;
   c.sx=0;
   c.sy=0;
  if(!ClipBltInfo(&a5,&b5,&c)) return FALSE;
  */
        /* DIBSectionをDIBとして描画 */
            StretchDIBits(hdc, 0, 0, WIDTH*2, HEIGHT*2,
                0, 0, WIDTH, HEIGHT, lpPixel, &biInfo,
                DIB_RGB_COLORS,SRCCOPY);
            CalcFPS(hdc);
            EndPaint(hwnd, &ps);
            DeleteObject(SelectObject(hdc , GetStockObject(WHITE_BRUSH)));
        }
        return 0;
    case WM_DESTROY: /* ウインドウ破棄時 */
        SelectObject(hdcBMP, hBMPOLD);
        DeleteObject(hdcBMP);
        DeleteObject(hBMP);
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, iMsg, wParam, lParam);
}

007:グーローシェーディング
グーローシェーディングは、スムースシェーディングの中では
軽い計算量で済みます。頂点ベクトルで頂点カラーとして乗算して
色を付けて、グラデーションをかけて滑らかに見せる手法です。
グラデーションを行うには前述の直線のアルゴリズムで使った
変化中=(変化前*(1-A)+変化後*A)が使えます。
頂点(X1,Y1)と(X2,Y2),(X2,Y2)と(X3,Y3),(X1,Y1)と(X2,Y2)に
それぞれグラデーションを少しずつ変化させればOKです。

blog-body_9508d66a-4867-47c6-8158-1e8ba2665d25_頂点点ベクトル.jpg
正規化頂点ベクトル.png


notitle20240416.png


gouraud.png

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define WIDTH 320
#define HEIGHT 240
int min_[HEIGHT];
int max_[HEIGHT];
#define SCREENHEIGHT HEIGHT
#define SCALE 240.0f
int MAXVTX=0;//最大の頂点数
int MAXPOL=0;//最大のポリゴン数
int LastLine=0;
BITMAPINFO biInfo;
LPDWORD lpPixel;
struct TClipSize
{
 int width,height;
};
struct TClipBltInfo
{
 int sw,sh;
 int sx,sy;
 int dx,dy;
};
HBITMAP hBMP, hBMPOLD;
HDC hdcBMP;
HDC HdcGlobal;
char FileStr[10000][800];
int BMP[256][256];
int minX[HEIGHT];//最小バッファ
int maxX[HEIGHT];//最大バッファ
int minX2[HEIGHT];
int maxX2[HEIGHT];
int minU[HEIGHT];
int maxU[HEIGHT];
int minV[HEIGHT];
int maxV[HEIGHT];
int cmin[HEIGHT];
int cmax[HEIGHT];
void TRIANGLE(int x1,int y1,int x2,int y2,int x3,int y3,int col);//三角形を描画する関数
void LINE(int x1,int y1,int x2,int y2,int col);//線を描く関数
void PSET(int x,int y,int col);//点を打つ関数
void Projection2DAxisFrom3DAxis(HWND hwnd);
void SetXYZ(int num,double x,double y,double z);
void Init();
inline void TRIANGLE2(int x1,int y1,int x2,int y2,int x3,int y3,int c1,int c2,int c3);
BOOL ClipBltInfo(TClipSize *src,TClipSize *dest,TClipBltInfo *info);
typedef struct VTX{
 double x,y,z;
 int count;
 int R,G,B;
}VTX;
typedef struct XYZ{
    double x;
    double y;
    double z;
 int count;
}XYZ;
typedef struct XY{
    double x;
    double y;
}XY;
typedef struct COL{
 int r;
 int g;
 int b;
}COL;
#define RAD (3.14159265/180.0)
#define MAX_XYZ 5000
XYZ Pnt[MAX_XYZ];
XY Pnt2[MAX_XYZ];
XYZ vhMin[HEIGHT];
XYZ vhMax[HEIGHT];
int Poly[5000][4];
COL Cl[5000];
double vpx=1.0f,vpy=1.0f,vpz=-800.0f;
double D=424;
//XYZ vvv[5000];//全ての頂点の法線をクリアする
int vint[5000][3];
void Normalize(XYZ *a);//正規化関Calc
/*#ifdef _DEBUG
# define MyOutputDebugString( str, ... ) \
      { \
        char c[512]; \
        sprintf( c, str, __VA_ARGS__ ); \
        OutputDebugString( c ); \
      }
#else
//# define MyOutputDebugString( str, ... ) // 空実装
#endif
// CreateDIBSection32FromFile248.cpp
            */
BOOL ClipBltInfo(TClipSize *src,TClipSize *dest,TClipBltInfo *info)
{
 if((info->sw+info->dx)<=0) return FALSE;
 if((info->sh+info->dy)<=0) return FALSE;
 if(info->dx>=dest->width) return FALSE;
 if(info->dy>=dest->height) return FALSE;
 if((info->sx)>=src->width) return FALSE;
 if((info->sy)>= src->height) return FALSE;
 if((info->sx+info->sw)<0)return FALSE;
 if((info->sy+info->sh)<0) return FALSE;
 if((info->dx+info->sw)>=src->width) info->sw=(src->width-info->sx);
 if((info->dy+info->sh)>=src->height) info->sh=(src->height-info->sy);
 if(info->sx<0)
 {
  info->dx=info->dx+(-info->sx);
  info->sw=info->sw-(-info->sx);
  info->sx=0;
 }
 if(info->sy<0)
 {
  info->dy=info->dy+(-info->sy);
  info->sh=info->sh-(-info->sy);
  info->sy=0;
 }
 if(info->dx<0)
 {
  info->sx=info->sx+(-info->dx);
  info->sw=info->sw-(-info->dx);
  info->dx=0;
 }
 if(info->dy<0)
 {
  info->sy=info->sy+(-info->dy);
  info->sh=info->sh-(-info->dy);
  info->dy=0;
 }
 if((info->dx+info->sw)>dest->width) info->sw=dest->width-info->dx;
 if((info->dy+info->sh)>dest->height) info->sh=dest->height-info->dy;
 if(info->sw<1) return false;
 if(info->sh<1) return false;
 return true;
}
int CreateDIBSection32FromFile248(char *lpFileName,HBITMAP *lphBmp,LPDWORD *lppPixel,BITMAPINFO *lpBmpInfo);
void DeleteDIBSection32(HBITMAP *lphBmp);
void ScanUVEdge(double u1,double v1,double u2,double v2,int x1,int y1,int x2,int y2);
void readRGB(int u,int v,int *r,int *g,int *b);
int CreateDIBSection32FromFile248(char *lpFileName,HBITMAP *lphBmp,LPDWORD *lppPixel,BITMAPINFO *lpBmpInfo)
{
 HANDLE fh;
 DWORD dwFileSize,dwReadSize;
 LPBYTE lpbuf;
 LPBITMAPFILEHEADER lpbmpfh;
 LPBITMAPINFO lpbmpInfo;
 LPBYTE lpbmpPixel;
 LPRGBQUAD lpColorTable;
 int bitCount,iWidth,iHeight,iLength,x,y;
 fh=CreateFile(lpFileName,GENERIC_READ,0,NULL,
  OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 if(fh==INVALID_HANDLE_VALUE){
  MessageBox(NULL,"ファイルが開けません",lpFileName,MB_OK);
  return -1;
 }
 dwFileSize=GetFileSize(fh,NULL);
 lpbuf=(LPBYTE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwFileSize);
 ReadFile(fh,lpbuf,dwFileSize,&dwReadSize,NULL);
 CloseHandle(fh);
 lpbmpfh=(LPBITMAPFILEHEADER)lpbuf;
 lpbmpInfo=(LPBITMAPINFO)(lpbuf+sizeof(BITMAPFILEHEADER));
 bitCount=lpbmpInfo->bmiHeader.biBitCount;
 if(lpbmpfh->bfType!=('M'<<8)+'B' || (bitCount!=24 && bitCount!=8)){
  HeapFree(GetProcessHeap(),0,lpbuf);
     MessageBox(NULL,"24 or 8 ビットBMPファイルしか読み込めません",lpFileName,MB_OK);
  return -2;
 }
 lpbmpPixel=lpbuf + lpbmpfh->bfOffBits;
 iWidth=lpbmpInfo->bmiHeader.biWidth;
 iHeight=lpbmpInfo->bmiHeader.biHeight;
 if(iWidth*(bitCount/8)%4) iLength=iWidth*(bitCount/8)+(4-iWidth*(bitCount/8)%4);
 else iLength=iWidth*(bitCount/8);
 CopyMemory(lpBmpInfo,&lpbmpInfo->bmiHeader,sizeof(BITMAPINFOHEADER));
 lpBmpInfo->bmiHeader.biBitCount=32;
 *lphBmp=CreateDIBSection(NULL,lpBmpInfo,DIB_RGB_COLORS,(void**)lppPixel,NULL,0);
 switch(bitCount){
  case 24:
   for(y=0;y<iHeight;y++)
    for(x=0;x<iWidth;x++)
     CopyMemory(*lppPixel+x+y*iWidth,lpbmpPixel+x*3+y*iLength,3);
   break;
  case 8:
   lpColorTable=lpbmpInfo->bmiColors;
   for(y=0;y<iHeight;y++)
    for(x=0;x<iWidth;x++)
     CopyMemory(*lppPixel+x+y*iWidth,lpColorTable+lpbmpPixel[x+y*iLength],3);
   break;
 }
 HeapFree(GetProcessHeap(),0,lpbuf);
 return 0;
}
void DeleteDIBSection32(HBITMAP *lphBmp)
{
 if(*lphBmp!=NULL){
  DeleteObject(*lphBmp);
  *lphBmp=NULL;
 }
}
long int FPSCount=0;
void GF(int x1,int y1,int x2,int y2,int col)
{
 for(int y=y1;y<y2;y++)
 {
  for(int x=x1;x<x2;x++)
  {
   BMP[y][x]=col;
  }
 }
}
void DrawCheckMap()
{
 static int ix=0;
 int N=32;
 for(int i=0;i<256/N;i++)
 {
  if(i%2==0) ix^=1;
  for(int j=0;j<256/N;j++)
  {
   if(j%2==0) ix^=1;
   GF(i*N,j*N,i*N+(N-1),j*N+(N-1),RGB(ix*255,ix*255,ix*255));
  }
 }
 //BITMAP[i][j]=i;
}
void DrawTextureMapping(int x1,int y1,int x2,int y2,int x3,int y3)
{
 //UV座標の初期化を忘れずに
 //minX,maxXの初期化をわすれずに
 for(int i=0;i<HEIGHT;i++)
 {
  minX[i]= 100000;
  //minY[i]= 100000;
  minU[i]= 100000;
  minV[i]= 100000;
  maxX[i]=-100000;
  //maxY[i]=-100000;
  maxU[i]=-100000;
  maxV[i]=-100000;
 }
 DrawCheckMap();
 ScanUVEdge(0.0f,0.0f,1.0f,0.0f,x1,y1,x2,y2);
 ScanUVEdge(1.0f,0.0f,0.0f,1.0f,x2,y2,x3,y3);
 ScanUVEdge(0.0f,1.0f,0.0f,0.0f,x3,y3,x1,y1);
 //UとVの対応付けを行う関数
 int r,g,b;
 int u,v,x;
 for(int y=0;y<HEIGHT;y++)
 {
  for(double i=0.0f;i<1.0f;i+=0.001f)
  {
   u=(0*(1.0f-i)+1*i);
   v=(1*(1.0f-i)+0*i);
   x=(minX[y]*(1.0f-i)+maxX[y]*i);
   readRGB(u,v,&r,&g,&b);
   //DrawRGB(x,y,r,g,b);
   PSET(x,y,RGB(b,g,r));
  }
 }
}
void ScanUVEdge(double u1,double v1,double u2,double v2,int x1,int y1,int x2,int y2)
{
     for(double i=0;i<1.0;i+=0.001)
     {
          int x=(x1*(1-i)+x2*i);
          int y=(y1*(1-i)+y2*i);
          double u=(u1*(1-i)+u2*i);
          double v=(v1*(1-i)+v2*i);
          if(minX[y]>x) minX[y]=x;
          if(maxX[y]<x) maxX[y]=x;
          if(minU[y]>u) minU[y]=u;
          if(maxU[y]<u) maxU[y]=u;
          if(minV[y]>v) minV[y]=v;
          if(maxV[y]<v) maxV[y]=v;
     }
}
void readRGB(int u,int v,int *r,int *g,int *b)
{
      int u2=u*256;
      int v2=v*256;//BITMAPはSizeは256x256固定(^^;
      *r=BMP[u2][v2];
      *g=((BMP[u2][v2])>>8) & 0xFF;
      *b=((BMP[u2][v2])>>16) & 0xFF;
}
void DrawSquare(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,
    int c1,int c2,int c3,int c4)
{
 TRIANGLE2(x1,y1,x2,y2,x4,y4,c1,c2,c4);
 TRIANGLE2(x2,y2,x3,y3,x4,y4,c2,c3,c4);
}
inline void FASTScanEdge(int x1,int y1,int x2,int y2,int c1,int c2)
{
 int b1=(c1>>16) & 0xFF;
 int g1=(c1>>8) & 0xFF;
 int r1=c1 & 0xFF;
 int b2=(c2>>16) & 0xFF;
 int g2=(c2>>8) & 0xFF;
 int r2=c2 & 0xFF;
    for(int i=0;i<=1024;i++)
    {
        int ax=x1*((1<<10)-i)+x2*i>>10;
        int ay=y1*((1<<10)-i)+y2*i>>10;
        int k=((ay-(y1<<10)))/(y2-y1+1);
        if(ay<0 || ay>=HEIGHT) continue;
  if(minX[ay]>ax)
  {
   minX[ay]=ax;
   cmin[ay]=RGB( ((1<<10)-k)*b1+k*b2>>10,((1<<10)-k)*g1+k*g2>>10, ((1<<10)-k)*r1+k*r2>>10);
   PSET(ax,ay,cmin[ay]);
  }
  if(maxX[ay]<ax)
  {
   maxX[ay]=ax;
   cmax[ay]=RGB( ((1<<10)-k)*b1+k*b2>>10,
    ((1<<10)-k)*g1+k*g2>>10,
    ((1<<10)-k)*r1+k*r2>>10);
   PSET(ax,ay,cmax[ay]);
  }
    }
}
inline void FASTTRIANGLE(int x1,int y1,int x2,int y2,int x3,int y3,int c1,int c2,int c3)
{
 for(int i=0;i<HEIGHT;i++)
 {
  minX[i]=65536;
  maxX[i]=-65536;
  cmin[i]=RGB(0,0,0);
  cmax[i]=RGB(0,0,0);
 }
    FASTScanEdge(x1,y1,x2,y2,c1,c2);
    FASTScanEdge(x1,y1,x3,y3,c1,c3);
    FASTScanEdge(x2,y2,x3,y3,c2,c3);
    for(int y=0;y<HEIGHT;y++)
    {
        if(minX[y]==65536 && maxX[y]==-65536) continue;
        for(int x=minX[y];x<=maxX[y];x++)
  {
   int r1=cmin[y] & 0xFF;
   int g1=cmin[y]>>8 & 0xFF;
   int b1=cmin[y]>>16 & 0xFF;
   int r2=cmax[y] & 0xFF;
   int g2=cmax[y]>>8 & 0xFF;
   int b2=cmax[y]>>16 & 0xFF;
   int j=((x-minX[y])<<8)/(maxX[y]-minX[y]+1);
   int r=r1*((1<<8)-j)+(r2)*j>>8;
   int g=g1*((1<<8)-j)+(g2)*j>>8;
   int b=b1*((1<<8)-j)+(b2)*j>>8;
   int NewR=r;
   int NewG=g;
   int NewB=b;
   if(NewR<0) NewR=0; if(NewR>255) NewR=255;
   if(NewG<0) NewG=0; if(NewG>255) NewG=255;
   if(NewB<0) NewB=0; if(NewB>255) NewB=255;
            PSET(x,y,RGB(NewB,NewG,NewR));
  }
    }
}
void CalcFPS(HDC hdc)
{
 char str[100];
 static int FPS=0;
 static long int time=GetTickCount();
 //FPSCount++;
 if(GetTickCount()-time>1000)
 {
  time=GetTickCount();
  FPS=FPSCount;
  FPSCount=0;
 }else{
  FPSCount++;
 }
 sprintf(str,"FPS=%d",FPS);
 TextOut(hdc,0,0,str,strlen(str));
 //TextOut(hdc,0,90,"PRESS SPACE KEY!!",strlen("PRESS SPACE KEY!!"));
}
void SetColor(int num,int r,int g,int b)
{
 Cl[num].r=r;
 Cl[num].g=g;
 Cl[num].b=b;//そのポリゴンの色を指定する
}
XYZ CrossProduct(XYZ a,XYZ b)
{
    //23-32 31-13 12-21
    //YZ-ZY ZX-XZ XY-YX
    //aY*bZ-aZ*bY aZ*bX-aX*bZ aX*bY-aY*bX
    XYZ c;
    c.x=(a.y*b.z)-(a.z*b.y);
    c.x=(a.z*b.x)-(a.x*b.z);
    c.x=(a.x*b.y)-(a.y*b.x);
    return c;
}
double DotProduct(XYZ a,XYZ b)
{
 return a.x*b.x+a.y*b.y+a.z*b.z;
}
void Rotate(int X,int Y,int Z)
{
 int i;
 double cosSita=cos(Z*RAD);
 double sinSita=sin(Z*RAD);
    for(i=0;i<MAXVTX;i++)//Z軸、つまり2次元的な回転を行う(矢印キー右左で左右に回転する)
    {
        double x2=Pnt[i].x*cosSita-Pnt[i].y*sinSita;
        double y2=Pnt[i].x*sinSita+Pnt[i].y*cosSita;
        double z2=Pnt[i].z;
  //double x2_=vvv[i].x*cosSita-vvv[i].y*sinSita;
        //double y2_=vvv[i].x*sinSita+vvv[i].y*cosSita;
        //double z2_=vvv[i].z;
        Pnt[i].x=x2;
        Pnt[i].y=y2;
        Pnt[i].z=z2;
  //vvv[i].x=x2_;
        //vvv[i].y=y2_;
        //vvv[i].z=z2_;
    }
 double cosSita2=cos(X*RAD);
 double sinSita2=sin(X*RAD);
    for(i=0;i<MAXVTX;i++)//X軸、つまり奥か手前かに回転する(矢印キー↑↓で↑↓に回転する)
    {
        double y2=Pnt[i].y*cosSita2-Pnt[i].z*sinSita2;
        double z2=Pnt[i].y*sinSita2+Pnt[i].z*cosSita2;
        double x2=Pnt[i].x;
  //double y2_=vvv[i].y*cosSita2-vvv[i].z*sinSita2;
        //double z2_=vvv[i].y*sinSita2+vvv[i].z*cosSita2;
        //double x2_=vvv[i].x;
        Pnt[i].x=x2;
        Pnt[i].y=y2;
        Pnt[i].z=z2;
  //vvv[i].x=x2_;
        //vvv[i].y=y2_;
        //vvv[i].z=z2_;
    }
    for(i=0;i<MAXVTX;i++)//ここはY軸回転だが、今のところ使わない
    {
        double x3=Pnt[i].z*sin(Y*RAD)+Pnt[i].x*cos(Y*RAD);
        double z3=Pnt[i].z*cos(Y*RAD)-Pnt[i].x*sin(Y*RAD);
        double y3=Pnt[i].y;
  //double x3_=vvv[i].z*sin(Y*RAD)+vvv[i].x*cos(Y*RAD);
        //double z3_=vvv[i].z*cos(Y*RAD)-vvv[i].x*sin(Y*RAD);
        //double y3_=vvv[i].y;
        Pnt[i].x=x3;
        Pnt[i].y=y3;
        Pnt[i].z=z3;
  //vvv[i].x=x3_;
        //vvv[i].y=y3_;
        //vvv[i].z=z3_;
    }
}
void Projection2DAxisFrom3DAxis(HWND hwnd)
{
 HDC hdc = GetDC(hwnd);
    for(int i=0;i<MAXVTX;i++)
    {
        Pnt2[i].x=(Pnt[i].x*D)/(Pnt[i].z-vpz)+(WIDTH/2);
        Pnt2[i].y=-(Pnt[i].y*D)/(Pnt[i].z-vpz)+(HEIGHT/2);
        //PSET(Pnt2[i].x,Pnt2[i].y,0x00ffffff);
  //char str[100];
  //sprintf(str,"%d",i);
  //TextOut(hdc,Pnt2[i].x,Pnt2[i].y,str,strlen(str));
  //TextOut(hdc, 0, i*20, str, strlen(str));
    }
}
void SetPoly(int num,int n1,int n2,int n3,int n4)
{
 Poly[num][0]=n1;//頂点番号を指定
 Poly[num][1]=n2;
 Poly[num][2]=n3;
 Poly[num][3]=n4;
}
void SetPoly(int num,int n1,int n2,int n3)
{
 Poly[num][0]=n1;//頂点番号を指定
 Poly[num][1]=n2;
 Poly[num][2]=n3;
}
void SetPoly(int n1,int n2,int n3)
{
 static int num=0;
 Poly[num][0]=n1;//頂点番号を指定
 Poly[num][1]=n2;
 Poly[num][2]=n3;
 num++;
}
void SetXYZ(int num,double x,double y,double z)
{
    if(num<0 || num>=MAX_XYZ) return;
    Pnt[num].x=x;//頂点座標を指定
    Pnt[num].y=y;
    Pnt[num].z=z;
}
void Init()
{
    SetXYZ(0,-100.0,-100.0,-100.0);//8つの頂点を指定している
    SetXYZ(1, 100.0,-100.0,-100.0);
    SetXYZ(2, 100.0, 100.0,-100.0);
    SetXYZ(3,-100.0, 100.0,-100.0);
    SetXYZ(4,-100.0,-100.0, 100.0);
    SetXYZ(5, 100.0,-100.0, 100.0);
    SetXYZ(6, 100.0, 100.0, 100.0);
    SetXYZ(7,-100.0, 100.0, 100.0);
 SetPoly(0,1,2);
 SetPoly(2,3,0);
 SetPoly(3,4,0);
 SetPoly(3,7,4);
 SetPoly(7,6,5);
 SetPoly(7,5,4);
 SetPoly(6,2,1);
 SetPoly(6,1,5);
 SetPoly(5,1,0);
 SetPoly(0,4,5);
 SetPoly(6,7,3);
 SetPoly(6,3,2);
 MAXVTX = 7;
 SetColor(0,255,255,0);//それぞれのポリゴンの色を設定している
 SetColor(1,255,0,255);
 SetColor(2,0,255,255);
 SetColor(3,255,0,0);
 SetColor(4,0,0,255);
 SetColor(5,255,255,255);
 SetColor(6,255,120,255);
 SetColor(7,0,125,255);
 SetColor(8,255,0,255);
 SetColor(9,0,255,255);
 SetColor(10,255,255,0);
 SetColor(11,0,255,255);
 SetColor(12,255,0,255);
}
BOOL SetClientSize(HWND hWnd, int width, int height)
{
 RECT rw, rc;
 ::GetWindowRect(hWnd, &rw);
 ::GetClientRect(hWnd, &rc);
 int new_width = (rw.right - rw.left) - (rc.right - rc.left) + width;
 int new_height = (rw.bottom - rw.top) - (rc.bottom - rc.top) + height;
 return ::SetWindowPos(hWnd, NULL, 0, 0, new_width, new_height, SWP_NOMOVE | SWP_NOZORDER);
}
inline void PSET(int x, int y, int col)
{
 int R = (col >> 16) & 0xFF;
 int G = (col >> 8) & 0xFF;
 int B = col & 0xFF;
 int address;
 //点を打つ
 if (x >= 0 && y >= 0 && x < WIDTH && y < HEIGHT)
 {
  address = x + (y * WIDTH);
  lpPixel[address] = RGB(B,G,R);
 }
}
void LINE(int x1,int y1,int x2,int y2,int col)
{
    //線分を描画する
    for(int i=0;i<=256;i++)
    {
        int ax=x1*(256-i)+x2*i>>8;
        int ay=y1*(256-i)+y2*i>>8;
        PSET(ax,ay,col);
    }
}
inline void ClearScreen()
{
 //毎回ループの最初で画面を初期化する
 for(int i=0;i<HEIGHT;i++)
 {
  for(int j=0;j<WIDTH;j++)
  {
   PSET(j,i,0x00000000);
   //PSET(i,j,0x00000000);
  }
 }
}
inline void ScanEdge(int x1,int y1,int x2,int y2)
{
 //2次元的なスキャン
    for(int i=0;i<=1024;i++)
    {
        int ax=x1*((1<<10)-i)+x2*i>>10;
        int ay=y1*((1<<10)-i)+y2*i>>10;
        if(ay<0 || ay>=HEIGHT) continue;
  if(minX[ay]>ax) minX[ay]=ax;
  if(maxX[ay]<ax) maxX[ay]=ax;
    }
}
inline void ScanEdge(int x1,int y1,int x2,int y2,int c1,int c2)
{
 int r1=(c1>>16) & 0xFF;
 int g1=(c1>>8) & 0xFF;
 int b1=c1 & 0xFF;
 int r2=(c2>>16) & 0xFF;
 int g2=(c2>>8) & 0xFF;
 int b2=c2 & 0xFF;
    for(int i=0;i<1024;i++)//0.0~1.0を、0~1024に直す
    {
        int ax=(x1*(1024-i)+x2*i)>>10;//線形補間の固定小数点処理化(X成分
        int ay=(y1*(1024-i)+y2*i)>>10;//(固定小数点(Y成分
       // int k=(ay-y1)*100/(y2-y1);//0.0~1.0を0~256に直す
        if(ay<0 || ay>=HEIGHT) return;
  if(minX2[ay]>ax)//minなX(左側の線分)
  {
   minX2[ay]=ax;
   int b=((1024-i)*b1+i*b2)>>10;
   int g=((1024-i)*g1+i*g2)>>10;
   int r=((1024-i)*r1+i*r2)>>10;
   if(r<0) r=0; if(r>255) r=255;
   if(g<0) g=0; if(g>255) g=255;
   if(b<0) b=0; if(b>255) b=255;
   cmin[ay]=RGB(r,g,b);
   PSET(ax,ay,cmin[ay]);
  }
  if(maxX2[ay]<ax)//maxなX(右側の線分)
  {
   maxX2[ay]=ax;
   int b=((1024-i)*b1+i*b2)>>10;
   int g=((1024-i)*g1+i*g2)>>10;
   int r=((1024-i)*r1+i*r2)>>10;
   if(r<0) r=0; if(r>255) r=255;
   if(g<0) g=0; if(g>255) g=255;
   if(b<0) b=0; if(b>255) b=255;
   cmax[ay]=RGB(r,g,b);
   PSET(ax,ay,cmax[ay]);
  }
    }
}
void FillGraRect(int x1,int y1,int x2,int y2,
     int r1,int g1,int b1,
     int r2,int g2,int b2)
{
 for(int i=x1;i<x2;i++)
 {
  double d=(i-x1)/(double)(x2-x1);
  int r=r1*(1-d)+r2*d;
  int g=g1*(1-d)+g2*d;
  int b=b1*(1-d)+b2*d;
  LINE(i,y1,i,y2,RGB(b,g,r));
 }
}
inline void ScanEdge3(int x1,int y1,int x2,int y2,XYZ v1,XYZ v2)
{
    for(int i=0;i<1024;i++)//0.0~1.0を、0~1024に直す
    {
  //double j=(i<<10)/101.0;
        int ax=(x1*(1024-i)+x2*i)/1024;//線形補間の固定小数点処理化(X成分
        int ay=(y1*(1024-i)+y2*i)/1024;//(固定小数点(Y成分
       // int k=(ay-y1)*100/(y2-y1);//0.0~1.0を0~256に直す
        if(ay<0 || ay>=HEIGHT) return;
  if(minX2[ay]>ax)//minなX(左側の線分)
  {
   minX2[ay]=ax;
   vhMin[ay].x=((1024-i)*v1.x+i*v2.x)/1024;
   vhMin[ay].y=((1024-i)*v1.y+i*v2.y)/1024;
   vhMin[ay].z=((1024-i)*v1.z+i*v2.z)/1024;
   Normalize(&vhMin[ay]);
   //double InVx=(ax*D)/(vhMin[ay].z+vpz)+160;
   //double InVy=(ay*D)/(vhMin[ay].z+vpz)+120;
   //LINE(InVx,InVy,ax,ay,RGB(0,0,255));
   //cmin[ay]=RGB(r,g,b);
   //PSET(ax,ay,cmin[ay]);
  }
  if(maxX2[ay]<ax)//maxなX(右側の線分)
  {
   maxX2[ay]=ax;
   vhMax[ay].x=((1024-i)*v1.x+i*v2.x)/1024;
   vhMax[ay].y=((1024-i)*v1.y+i*v2.y)/1024;
   vhMax[ay].z=((1024-i)*v1.z+i*v2.z)/1024;
   Normalize(&vhMax[ay]);
   //cmax[ay]=RGB(r,g,b);
   //PSET(ax,ay,cmax[ay]);
  }
    }
}
inline void TRIANGLE3(int x1,int y1,int x2,int y2,int x3,int y3,XYZ v1,XYZ v2,XYZ v3,XYZ lig)
{
 for(int i=0;i<HEIGHT;i++)
 {
  minX2[i]=65816;
  maxX2[i]=-65816;
  cmin[i]=RGB(0,0,0);
  cmax[i]=RGB(0,0,0);
  vhMin[i].x=0.0f;
  vhMin[i].y=0.0f;
  vhMin[i].z=0.0f;
  vhMax[i].x=0.0f;
  vhMax[i].y=0.0f;
  vhMax[i].z=0.0f;
 }
    ScanEdge3(x1,y1,x2,y2,v1,v2);
    ScanEdge3(x2,y2,x3,y3,v2,v3);
    ScanEdge3(x3,y3,x1,y1,v3,v1);
    for(int y=0;y<HEIGHT;y++)
    {
        if(minX2[y]==65816 || maxX2[y]==-65816) continue;
        for(int x=minX2[y];x<=maxX2[y];x++)
  {
   int j=((x-minX2[y]))*1024/(maxX2[y]-minX2[y]+0.001);
   XYZ vv={0};
   vv.x=(vhMin[y].x*(1024-j)+(vhMax[y].x)*j)/1024;
   vv.y=(vhMin[y].y*(1024-j)+(vhMax[y].y)*j)/1024;
   vv.z=(vhMin[y].z*(1024-j)+(vhMax[y].z)*j)/1024;
   Normalize(&vv);
   /*
   double len=sqrt(vv.x*vv.x+vv.y*vv.y+vv.z*vv.z);
   vv.x/=len;
   vv.y/=len;
   vv.z/=len;
   */
   Normalize(&lig);
   double R=lig.x*vv.x+lig.y*vv.y+lig.z*vv.z;
   double G=lig.x*vv.x+lig.y*vv.y+lig.z*vv.z;
   double B=lig.x*vv.x+lig.y*vv.y+lig.z*vv.z;
   double R2=pow(R,55);
   double G2=pow(G,55);
   double B2=pow(B,55);
   PSET(x,y,RGB(B2*255,G2*255,R*255));
  }
    }
}
inline void TRIANGLE2(int x1,int y1,int x2,int y2,int x3,int y3,int c1,int c2,int c3)
{
 for(int i=0;i<HEIGHT;i++)
 {
  minX2[i]=65816;
  maxX2[i]=-65816;
  cmin[i]=RGB(0,0,0);
  cmax[i]=RGB(0,0,0);
 }
    ScanEdge(x1,y1,x2,y2,c1,c2);
    ScanEdge(x2,y2,x3,y3,c2,c3);
    ScanEdge(x3,y3,x1,y1,c3,c1);
    for(int y=0;y<HEIGHT;y++)
    {
        if(minX2[y]==65816 || maxX2[y]==-65816) continue;
        for(int x=minX2[y];x<=maxX2[y];x++)
  {
   int r1=cmin[y]>>16 & 0xFF;
   int g1=cmin[y]>>8 & 0xFF;
   int b1=cmin[y] & 0xFF;
   int r2=cmax[y]>>16 & 0xFF;
   int g2=cmax[y]>>8 & 0xFF;
   int b2=cmax[y] & 0xFF;
   int j=((x-minX2[y])<<8)/(maxX2[y]-minX2[y]+1);
   int r=(r1*(256-j)+(r2)*j)>>8;
   int g=(g1*(256-j)+(g2)*j)>>8;
   int b=(b1*(256-j)+(b2)*j)>>8;
   int NewR=r;
   int NewG=g;
   int NewB=b;
   if(NewR<0) NewR=0; if(NewR>255) NewR=255;
   if(NewG<0) NewG=0; if(NewG>255) NewG=255;
   if(NewB<0) NewB=0; if(NewB>255) NewB=255;
            PSET(x,y,RGB(NewR,NewG,NewB));
  }
    }
}
inline void TRIANGLE(int x1,int y1,int x2,int y2,int x3,int y3,int col)
{
 for(int i=0;i<HEIGHT;i++)
 {
  minX[i]=65536;
  maxX[i]=-65536;
 }
    ScanEdge(x1,y1,x2,y2);
    ScanEdge(x1,y1,x3,y3);
    ScanEdge(x2,y2,x3,y3);
    for(int y=0;y<HEIGHT;y++)
    {
        if(minX[y]==65536 || maxX[y]==-65536) continue;
        for(int x=minX[y];x<=maxX[y];x++)
  {
            PSET(x,y,col);
  }
    }
}
void Normalize(XYZ *a)//正規化関Calc
{
   double len=sqrt(a->x*a->x+a->y*a->y+a->z*a->z);
   a->x/=len;
   a->y/=len;
   a->z/=len;
}
double CalcSpecular(XYZ eye,XYZ light,XYZ housen,XYZ n,XYZ buttai)
{
   XYZ RLine;
   XYZ RLight;
   XYZ Ref;
   RLine.x=eye.x-buttai.x;
   RLine.y=eye.y-buttai.y;
   RLine.z=eye.z-buttai.z;//逆視線ベクトルの計算
   Normalize(&RLine);//正規化
   RLight.x=light.x-buttai.x;
   RLight.y=light.y-buttai.y;
   RLight.z=light.z-buttai.z;//逆光線ベクトルの計算
   Normalize(&RLight);//正規化
   double ll=n.x*RLight.x+n.y*RLight.y+n.z*RLight.z;
   Ref.x=ll*2+n.x*RLight.x;
   Ref.x=ll*2+n.y*RLight.y;
   Ref.x=ll*2+n.z*RLight.z;//反射光線ベクトルの計算
   Normalize(&Ref);//正規化
   double a=Ref.x*RLine.x+Ref.y*RLine.y+Ref.z*RLine.z;//反射光線ベクトルと逆視線ベクトルの内積
   return pow(a,30);
}
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInst;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow){
 HWND hwMain;
 MSG msg;
 WNDCLASS wndclass;
 hInst = hInstance;
 wndclass.style = CS_HREDRAW | CS_VREDRAW;
 wndclass.lpfnWndProc = WndProc;
 wndclass.cbClsExtra = 0;
 wndclass.cbWndExtra = 0;
 wndclass.hInstance = hInstance;
 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
 wndclass.lpszMenuName = NULL;
 wndclass.lpszClassName = "CWindow";
 RegisterClass(&wndclass);
 hwMain = CreateWindow("CWindow", "Phong Shading(is Testing)",
          WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
          WIDTH*2+22,HEIGHT*2+36+6, NULL, NULL, hInstance, NULL);
    SetClientSize(hwMain,320*2,240*2);//ウィンドウサイズ丁度良いサイズに調整してくれる
 /* ウインドウを表示 */
 ShowWindow(hwMain, iCmdShow);
 UpdateWindow(hwMain);
 /* メッセージループ */
 while(GetMessage(&msg, NULL, 0, 0)) {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
 return msg.wParam;
}
inline void LINE2COL(int x1,int y1,int x2,int y2,int COL,int COL2)
{
 //線を描くのと左か右かを判断する関数
 int NewX,NewY;
 for(int j=0;j<256;j++)
 {
  NewX=x1*(256-j)+x2*j>>8;
  NewY=y1*(256-j)+y2*j>>8;
  int R1,R2,G1,G2,B1,B2;
  R1=(COL>>16) & 0xFF;
  G1=(COL>>8) & 0xFF;
  B1=(COL) & 0xFF;
  R2=(COL2>>16) & 0xFF;
  G2=(COL2>>8) & 0xFF;
  B2=(COL2) & 0xFF;
  int R=R1*(256-j)+R2*j>>8;
  int G=G1*(256-j)+G2*j>>8;
  int B=B1*(256-j)+B2*j>>8;
  PSET(NewX,NewY,RGB(R,G,B));
  if(min_[(int)NewY]>NewX){
   min_[(int)NewY]=NewX;
   cmin[(int)NewY]=RGB(R,G,B);
  }
  if(max_[(int)NewY]<NewX){
   max_[(int)NewY]=NewX;
   cmax[(int)NewY]=RGB(R,G,B);
  }
 }
}
int min_Y(int y1,int y2,int y3)
{
 if(y1<y2 && y1<y3) return y1;
 if(y2<y1 && y2<y3) return y2;
 if(y3<y1 && y3<y2) return y3;
}
int max_Y(int y1,int y2,int y3)
{
 if(y1>y2 && y1>y3) return y1;
 if(y2>y1 && y2>y3) return y2;
 if(y3>y1 && y3>y2) return y3;
}
inline void GouraudShade(int x1,int y1,int x2,int y2,int x3,int y3,int C1,int C2,int C3)
{
 //入れ忘れ(笑)
 for(int i=0;i<SCREENHEIGHT;i++)
 {
  min_[i]=65816;
  max_[i]=-65816;
  cmin[i]=RGB(0,0,0);
  cmax[i]=RGB(0,0,0);
 }
 //LINE2COL(x1,y1,x2,y2,C1,C2);
 //LINE2COL(x2,y2,x3,y3,C2,C3);
 //LINE2COL(x1,y1,x3,y3,C1,C3);
 ScanEdge(x1,y1,x2,y2,C1,C2);
 ScanEdge(x2,y2,x3,y3,C2,C3);
 ScanEdge(x3,y3,x1,y1,C3,C1);
 for(int Y=0;Y<HEIGHT;Y++)
 {
  if(min_[Y]==65816 || max_[Y]==-65816) continue;
  int R1=(cmin[Y]>>16) & 0xFF;
  int G1=(cmin[Y]>>8) & 0xFF;
  int B1=(cmin[Y]) & 0xFF;
  int R2=(cmax[Y]>>16) & 0xFF;
  int G2=(cmax[Y]>>8) & 0xFF;
  int B2=(cmax[Y]) & 0xFF;
  LINE2COL(min_[Y],Y,max_[Y],Y,RGB(R1,G1,B1),RGB(R2,G2,B2));
 }
}
void LoadOBJFile(char filename[10000],HWND hwnd)
{
 static int flag=0;
 FILE *fp;
 fp=fopen(filename,"r");
 if(fp==NULL)
 {
  MessageBox(NULL,"ファイルがありません。","OK?",MB_OK);
  SelectObject(hdcBMP, hBMPOLD);
  DeleteObject(hdcBMP);
  DeleteObject(hBMP);
  PostQuitMessage(0);
  return;
 }
 int i=0;
 int j=0;
 while(fgets(FileStr[i],50,fp)!=NULL)
 {
  j=0;
  //以下の内容が通用しないのでテキストエディタ(最悪Windowsのメモ帳でも可)
  //で空白を,(カンマ)に変換する必要がある、
  //通用した、改行の処理を忘れていただけのようだ。これで、objファイルは大丈夫のようだ
  while(FileStr[i][j])
  {
   if(FileStr[i][j]==' ') FileStr[i][j]=',';
   ++j;
   if(FileStr[i][j]=='\n') ++i;
  }
 }
 LastLine=i;//最後の行数を保存する
 char opecode[10000]={0};
 double XF,YF,ZF;
 int TriNum1,TriNum2,TriNum3,TriNum4;
 int k=0;
 for(i=0;i<LastLine;i++)
 {
   opecode[0]=FileStr[i][0];
   //CameraPos.D=535.0f;
   //CameraPos.Z=-810.0f;
   //PSET(400,300,GetColor(0,0,255));
   if(opecode[0]=='v')
   {
    sscanf(FileStr[i],"%c,%lf,%lf,%lf",
    opecode,&XF,&YF,&ZF);
    SetXYZ(k,XF*SCALE,YF*SCALE,ZF*SCALE);
    Projection2DAxisFrom3DAxis(hwnd);
    //i=0;
    ++k;
    MAXVTX=k;
   }
   if(opecode[0]=='f')
   {
    sscanf(FileStr[i],"%c,%d,%d,%d,%d",
    opecode,&TriNum1,&TriNum2,&TriNum3,&TriNum4);
    if(flag==0)
    {
     j=0;
     flag=1;
    }
    SetPoly(j,(int)TriNum1-1,(int)TriNum2-1,(int)TriNum3-1,(int)TriNum4-1);
    Projection2DAxisFrom3DAxis(hwnd);
    ++j;
    MAXPOL=j;
   }
 }
}
XYZ CalcCross(XYZ a,XYZ b,XYZ c)
{
 XYZ d={0.0f};
 XYZ a2,b2;
   a2.x=a.x-b.x;
   a2.y=a.y-b.y;
   a2.z=a.z-b.z;
   b2.x=a.x-c.x;
   b2.y=a.y-c.y;
   b2.z=a.z-c.z;
   Normalize(&a2);
   //double len=sqrt(a2.x*a2.x+a2.y*a2.y+a2.z*a2.z+0.1);
   //a2.x/=len;
   //a2.y/=len;
   //a2.z/=len;
   Normalize(&b2);
   //double len2=sqrt(b2.x*b2.x+b2.y*b2.y+b2.z*b2.z+0.1);
   //b2.x/=len2;
   //b2.y/=len2;
   //b2.z/=len2;
            //23-32 31-13 12-21
            //aY*bZ-aZ*bY aZ*bX-aX*bZ aX*bY-aY*bX
   d.x=a2.y*b2.z-a2.z*b2.y;
   d.y=a2.z*b2.x-a2.x*b2.z;
   d.z=a2.x*b2.y-a2.y*b2.x;
  return d;
}
double CalcDotProduct(XYZ a, XYZ b)
{
 return a.x * b.x + a.y * b.y + a.z * b.z;
}
int JisakuRGB(int R, int G, int B)
{
 if (R > 255) R = 255;
 if (G > 255) G = 255;
 if (B > 255) B = 255;
 if (R < 0) R = 0;
 if (G < 0) G = 0;
 if (B < 0) B = 0;
 return R << 16 | G << 8 << B;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
    HDC hdc;
    PAINTSTRUCT ps;
 static int DrawMode = 1;
 static int prevSpace = 0;
    switch (iMsg) {
    case WM_TIMER:
        {
            if(GetAsyncKeyState(VK_ESCAPE)<0)
                SendMessage(hwnd,WM_DESTROY,NULL,NULL);
            double X=0.0f;
            double Y=0.0f;
            double Z=0.0f;
            //Z+=0.1f;
            //Y+=0.1f;
            if(GetAsyncKeyState(VK_RIGHT)<0) Y=-2.5f;
            else if(GetAsyncKeyState(VK_LEFT)<0) Y=2.5f;
            else Y=0.0f;
            if(GetAsyncKeyState(VK_DOWN)<0) X=-2.5f;
            else if(GetAsyncKeyState(VK_UP)<0) X=2.5f;
            else X=0.0f;
   if (GetAsyncKeyState(VK_SPACE) < 0 && !prevSpace)
    DrawMode = (DrawMode + 1) & 3;
   prevSpace = GetAsyncKeyState(VK_SPACE) < 0;
            Rotate(X,Y,0);
            static int X1=0,X2=0;
            int n=8;
            InvalidateRect(hwnd,NULL,NULL);
        }
        return 0;
    case WM_CREATE:
       //MyOutputDebugString("起動しました。");
        //Init();//3次元座標を代入
 // SetXYZ(0,-100,-100,0);
 // SetXYZ(1,-100,100,0);
 // SetXYZ(2,100,100,0);
 // SetXYZ(3,100,-100,0);
 /*SetXYZ(0,-100.0,-100.0,-100.0);//8つの頂点を指定している
    SetXYZ(1, 100.0,-100.0,-100.0);
    SetXYZ(2, 100.0, 100.0,-100.0);
    SetXYZ(3,-100.0, 100.0,-100.0);
  SetPoly( 0,1,2);
  SetPoly(2,3,0);
*/
  //Projection2DAxisFrom3DAxis(hwnd);
   /*
   0 3
   ********
   *++++++*
   *++++++*
   *++++++*
   ********
   1 2
   */
        //LoadOBJFile("./womanbody.obj",hwnd);
        //LoadOBJFile("./heimen.obj",hwnd);//cube.obj
        //LoadOBJFile("./DO-NATSU.obj",hwnd);
  LoadOBJFile("./do-natsu.obj",hwnd);
        SetTimer(hwnd,100,1000/60,NULL);
        /* BITMAPINFOをゼロクリア */
        ZeroMemory(&biInfo, sizeof(BITMAPINFO));
        /* BITMAPINFO設定 */
        biInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        biInfo.bmiHeader.biWidth = WIDTH;
        biInfo.bmiHeader.biHeight = -HEIGHT;
        biInfo.bmiHeader.biPlanes = 1;
        biInfo.bmiHeader.biBitCount = 32;
        biInfo.bmiHeader.biCompression = BI_RGB;
        /* ウインドウのDCを取得 */
        hdc = GetDC(hwnd);
        /* biInfoの形式でDIBSectionを作成 */
        hBMP =CreateDIBSection(hdc, &biInfo, DIB_RGB_COLORS, (LPVOID*)(&lpPixel), NULL, 0);
        /* DIBSection用のメモリDCを作成 */
        hdcBMP = CreateCompatibleDC(hdc);
        /* メモリDCにDIBSectionを選択 */
        hBMPOLD = (HBITMAP)SelectObject(hdcBMP, hBMP);
        /* 不要になったウインドウのDCを解放 */
        ReleaseDC(hwnd, hdc);
        return 0;
    case WM_PAINT:
        {
  int i;
        hdc = BeginPaint(hwnd, &ps);
        ClearScreen();//画面を消す
        //PSET(320,240,0x00ff0000);//点を打つ
        //LINE(320,240,640,380,0x00ff0000);
  TRIANGLE2(80,50,10,140,260,80,RGB(255,0,0),RGB(0,255,0),RGB(0,0,255));
        Projection2DAxisFrom3DAxis(hwnd);//透視投影
  //PSET(160, 120, 0x00ff0000);
        //PSET(320,240,0x00FFFFFF);
        XYZ vvv[1000];//全ての頂点の法線をクリアする
        for(i=0;i<MAXVTX;i++)
        {
            vvv[i].x=0.0f;//Clear
            vvv[i].y=0.0f;//Clear
            vvv[i].z=0.0f;//Clear
   vvv[i].count =0;
        }
        XYZ a[1000];
        XYZ b[1000];
        //XYZ n3;
        //頂点ベクトルは求まった(はず...)から、頂点カラーを面にある全ての頂点で求める
  //XYZ vpx=200,vpy=-120,vpz=100;
  for (i = 0; i < MAXVTX; i++)
  {
   int i1 = Poly[i][0];
   int i2 = Poly[i][1];
   int i3 = Poly[i][2];
   int i4 = Poly[i][3];
   XYZ n = CalcCross(Pnt[i1], Pnt[i2], Pnt[i3]);
   //外積を行った
   Normalize(&n);
   //正規化を行った
   XYZ n2 = CalcCross(Pnt[i3], Pnt[i4], Pnt[i2]);
   //外積を行った
   Normalize(&n2);
   //正規化を行った
   vvv[i1].x += n.x;
   vvv[i1].y += n.y;
   vvv[i1].z += n.z;
   vvv[i2].x += n.x;
   vvv[i2].y += n.y;
   vvv[i2].z += n.z;
   vvv[i3].x += n.x;
   vvv[i3].y += n.y;
   vvv[i3].z += n.z;
   vvv[i4].x += n2.x;
   vvv[i4].y += n2.y;
   vvv[i4].z += n2.z;
  }
  for (i = 0; i < MAXVTX; i++)
  {
   Normalize(&vvv[i]);
   //vvv[i].x/=vvv[i].count ;
   //vvv[i].y/=vvv[i].count ;
   //vvv[i].z/=vvv[i].count ;
  }
        //XYZ vpx=200,vpy=-120,vpz=100;
        for(i=0;i<MAXVTX;i+=1)
        {
            int i1=Poly[i][0];
            int i2=Poly[i][1];
            int i3=Poly[i][2];
   int i4 = Poly[i][3];
            XYZ n=CalcCross(Pnt[i1],Pnt[i2],Pnt[i3]);
   Normalize(&n);
            XYZ light={0,0,-5};
            double lenlight=sqrt((double)light.x*light.x+light.y*light.y+light.z*light.z+0.1);
            light.x/=lenlight;
            light.y/=lenlight;
            light.z/=lenlight;
   double spe1 = vvv[i1].x * light.x + vvv[i1].y * light.y + vvv[i1].z * light.z;
   double spe2 = vvv[i2].x * light.x + vvv[i2].y * light.y + vvv[i2].z * light.z;
   double spe3 = vvv[i3].x * light.x + vvv[i3].y * light.y + vvv[i3].z * light.z;
   double spe4 = vvv[i4].x * light.x + vvv[i4].y * light.y + vvv[i4].z * light.z;
            double ViewCos;
   //-------------------------------------------------------------------------
            double v7=ViewCos=(light.x*n.x+light.y*n.y+light.z*n.z);
   double p=pow(ViewCos, 50);
   if (p > 255) p = 255;
   //-------------------------------------------------------------------------
            //視線ベクトルと面ごとの法線ベクトルの内積
   //ViewCos<0
   if (ViewCos > 0)
   {
    if (!DrawMode) {
     TRIANGLE(Pnt2[Poly[i][1]].x, Pnt2[Poly[i][1]].y,
      Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      RGB(v7 * 255, v7 * 255, v7 * 255)
      //vvv[i1],vvv[i2],vvv[i3],light
     );
     TRIANGLE(Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      Pnt2[Poly[i][3]].x, Pnt2[Poly[i][3]].y,
      RGB(v7 * 255, v7 * 255, v7 * 255)
      //JisakuRGB(p * 255 * 50 + 30, p * 201 + 1 + 30, p * 201 + 1 + 30)
      //vvv[i1],vvv[i2],vvv[i3],light
     );
    }
    else if (DrawMode)
    {
     //TRIANGLE(Pnt2[Poly[i][1]].x, Pnt2[Poly[i][1]].y,
     // Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
     // Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
     // //vvv[i1],vvv[i2],vvv[i3],light
     //);
     //TRIANGLE(Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
     // Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
     // Pnt2[Poly[i][3]].x, Pnt2[Poly[i][3]].y,
     // RGB(v7 * 255, v7 * 255, v7 * 255)
      double p = pow(ViewCos, 30);
     double pgb = ViewCos * 1.0f;
     //double R2=pow(spe1*1,55);
     TRIANGLE2(Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      Pnt2[Poly[i][1]].x, Pnt2[Poly[i][1]].y,
      Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      //RGB(ViewCos*255,ViewCos*255,ViewCos*255)
      RGB(spe1*255, spe1 * 255, spe1 * 255),
      RGB(spe2 *255, spe2 * 255, spe2 * 255),
      RGB(spe3*255, spe3 * 255, spe3 * 255)
     );
     TRIANGLE2(Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      Pnt2[Poly[i][3]].x, Pnt2[Poly[i][3]].y,
      Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      //RGB(ViewCos*255,ViewCos*255,ViewCos*255)
      RGB(spe3 * 255, spe3 * 255, spe3 * 255),
      RGB(spe4 * 255, spe4 * 255, spe4 * 255),
      RGB(spe1 * 255, spe1 * 255, spe1 * 255)
     );
     //TRIANGLE(Pnt2[0].x, Pnt2[0].y, Pnt2[1].x, Pnt2[1].y, Pnt2[17].x, Pnt2[17].y, RGB(0, 0, 255));
    }
   }
        }
        //反時計回りの座標軸
        //三角形を表示する
            //DrawTextureMapping(240,0,0,120,240,0);
            //FillGraRect(0,0,320,20,255,0,0,0,255,0);
  /*
  TClipSize a5,b5;
  a5.width =320;
  a5.height=240;
  b5.width =320;
  b5.height =240;
  TClipBltInfo c;
   c.dx=0;
   c.dy=0;
   c.sh=240;
   c.sw=320;
   c.sx=0;
   c.sy=0;
  if(!ClipBltInfo(&a5,&b5,&c)) return FALSE;
  */
        /* DIBSectionをDIBとして描画 */
            StretchDIBits(hdc, 0, 0, WIDTH*2, HEIGHT*2,
                0, 0, WIDTH, HEIGHT, lpPixel, &biInfo,
                DIB_RGB_COLORS,SRCCOPY);
            CalcFPS(hdc);
            EndPaint(hwnd, &ps);
            DeleteObject(SelectObject(hdc , GetStockObject(WHITE_BRUSH)));
        }
        return 0;
    case WM_DESTROY: /* ウインドウ破棄時 */
        SelectObject(hdcBMP, hBMPOLD);
        DeleteObject(hdcBMP);
        DeleteObject(hBMP);
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
008:フォンシェーディング
画素単位の頂点ベクトルを求めるアルゴリズムです。
光の当たり方に関しての画質はポリゴン(非レイトレーシング)
の中では一番良い(はず)です。

Phong.png
phong_test.png
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>


#define WIDTH 320
#define HEIGHT 240
int min_[HEIGHT];
int max_[HEIGHT];
#define SCREENHEIGHT HEIGHT
#define SCALE 240.0f
int MAXVTX=0;//最大の頂点数
int MAXPOL=0;//最大のポリゴン数
int LastLine=0;
BITMAPINFO biInfo;
LPDWORD lpPixel;
struct TClipSize
{
 int width,height;
};
struct TClipBltInfo
{
 int sw,sh;
 int sx,sy;
 int dx,dy;
};
HBITMAP hBMP, hBMPOLD;
HDC hdcBMP;
HDC HdcGlobal;
char FileStr[10000][800];
int BMP[256][256];
int minX[HEIGHT];//最小バッファ
int maxX[HEIGHT];//最大バッファ
int minX2[HEIGHT];
int maxX2[HEIGHT];
int minU[HEIGHT];
int maxU[HEIGHT];
int minV[HEIGHT];
int maxV[HEIGHT];
int cmin[HEIGHT];
int cmax[HEIGHT];
void TRIANGLE(int x1,int y1,int x2,int y2,int x3,int y3,int col);//三角形を描画する関数
void LINE(int x1,int y1,int x2,int y2,int col);//線を描く関数
void PSET(int x,int y,int col);//点を打つ関数
void Projection2DAxisFrom3DAxis(HWND hwnd);
void SetXYZ(int num,double x,double y,double z);
void Init();
inline void TRIANGLE2(int x1,int y1,int x2,int y2,int x3,int y3,int c1,int c2,int c3);
BOOL ClipBltInfo(TClipSize *src,TClipSize *dest,TClipBltInfo *info);
typedef struct VTX{
 double x,y,z;
 int count;
 int R,G,B;
}VTX;
typedef struct XYZ{
    double x;
    double y;
    double z;
 int count;
}XYZ;
typedef struct XY{
    double x;
    double y;
}XY;
typedef struct COL{
 int r;
 int g;
 int b;
}COL;
#define RAD (3.14159265/180.0)
#define MAX_XYZ 5000
XYZ Pnt[MAX_XYZ];
XY Pnt2[MAX_XYZ];
XYZ vhMin[HEIGHT];
XYZ vhMax[HEIGHT];
int Poly[5000][4];
COL Cl[5000];
double vpx=1.0f,vpy=1.0f,vpz=-800.0f;
double D=424;
//XYZ vvv[5000];//全ての頂点の法線をクリアする
int vint[5000][3];
void Normalize(XYZ *a);//正規化関Calc
/*#ifdef _DEBUG
# define MyOutputDebugString( str, ... ) \
      { \
        char c[512]; \
        sprintf( c, str, __VA_ARGS__ ); \
        OutputDebugString( c ); \
      }
#else
//# define MyOutputDebugString( str, ... ) // 空実装
#endif
// CreateDIBSection32FromFile248.cpp
            */
int FPSCount=0;
BOOL ClipBltInfo(TClipSize *src,TClipSize *dest,TClipBltInfo *info)
{
 if((info->sw+info->dx)<=0) return FALSE;
 if((info->sh+info->dy)<=0) return FALSE;
 if(info->dx>=dest->width) return FALSE;
 if(info->dy>=dest->height) return FALSE;
 if((info->sx)>=src->width) return FALSE;
 if((info->sy)>= src->height) return FALSE;
 if((info->sx+info->sw)<0)return FALSE;
 if((info->sy+info->sh)<0) return FALSE;
 if((info->dx+info->sw)>=src->width) info->sw=(src->width-info->sx);
 if((info->dy+info->sh)>=src->height) info->sh=(src->height-info->sy);
 if(info->sx<0)
 {
  info->dx=info->dx+(-info->sx);
  info->sw=info->sw-(-info->sx);
  info->sx=0;
 }
 if(info->sy<0)
 {
  info->dy=info->dy+(-info->sy);
  info->sh=info->sh-(-info->sy);
  info->sy=0;
 }
 if(info->dx<0)
 {
  info->sx=info->sx+(-info->dx);
  info->sw=info->sw-(-info->dx);
  info->dx=0;
 }
 if(info->dy<0)
 {
  info->sy=info->sy+(-info->dy);
  info->sh=info->sh-(-info->dy);
  info->dy=0;
 }
 if((info->dx+info->sw)>dest->width) info->sw=dest->width-info->dx;
 if((info->dy+info->sh)>dest->height) info->sh=dest->height-info->dy;
 if(info->sw<1) return false;
 if(info->sh<1) return false;
 return true;
}
void CalcFPS(HDC hdc)
{
 char str[100];
 static int FPS=0;
 static long int time=GetTickCount();
 //FPSCount++;
 if(GetTickCount()-time>1000)
 {
  time=GetTickCount();
  FPS=FPSCount;
  FPSCount=0;
 }else{
  FPSCount++;
 }
 sprintf(str,"FPS=%d",FPS);
 TextOut(hdc,0,0,str,strlen(str));
 //TextOut(hdc,0,90,"PRESS SPACE KEY!!",strlen("PRESS SPACE KEY!!"));
}
void SetColor(int num,int r,int g,int b)
{
 Cl[num].r=r;
 Cl[num].g=g;
 Cl[num].b=b;//そのポリゴンの色を指定する
}
XYZ CrossProduct(XYZ a,XYZ b)
{
    //23-32 31-13 12-21
    //YZ-ZY ZX-XZ XY-YX
    //aY*bZ-aZ*bY aZ*bX-aX*bZ aX*bY-aY*bX
    XYZ c;
    c.x=(a.y*b.z)-(a.z*b.y);
    c.x=(a.z*b.x)-(a.x*b.z);
    c.x=(a.x*b.y)-(a.y*b.x);
    return c;
}
double DotProduct(XYZ a,XYZ b)
{
 return a.x*b.x+a.y*b.y+a.z*b.z;
}
void Rotate(int X,int Y,int Z)
{
 int i;
 double cosSita=cos(Z*RAD);
 double sinSita=sin(Z*RAD);
    for(i=0;i<MAXVTX;i++)//Z軸、つまり2次元的な回転を行う(矢印キー右左で左右に回転する)
    {
        double x2=Pnt[i].x*cosSita-Pnt[i].y*sinSita;
        double y2=Pnt[i].x*sinSita+Pnt[i].y*cosSita;
        double z2=Pnt[i].z;
  //double x2_=vvv[i].x*cosSita-vvv[i].y*sinSita;
        //double y2_=vvv[i].x*sinSita+vvv[i].y*cosSita;
        //double z2_=vvv[i].z;
        Pnt[i].x=x2;
        Pnt[i].y=y2;
        Pnt[i].z=z2;
  //vvv[i].x=x2_;
        //vvv[i].y=y2_;
        //vvv[i].z=z2_;
    }
 double cosSita2=cos(X*RAD);
 double sinSita2=sin(X*RAD);
    for(i=0;i<MAXVTX;i++)//X軸、つまり奥か手前かに回転する(矢印キー↑↓で↑↓に回転する)
    {
        double y2=Pnt[i].y*cosSita2-Pnt[i].z*sinSita2;
        double z2=Pnt[i].y*sinSita2+Pnt[i].z*cosSita2;
        double x2=Pnt[i].x;
  //double y2_=vvv[i].y*cosSita2-vvv[i].z*sinSita2;
        //double z2_=vvv[i].y*sinSita2+vvv[i].z*cosSita2;
        //double x2_=vvv[i].x;
        Pnt[i].x=x2;
        Pnt[i].y=y2;
        Pnt[i].z=z2;
  //vvv[i].x=x2_;
        //vvv[i].y=y2_;
        //vvv[i].z=z2_;
    }
    for(i=0;i<MAXVTX;i++)//ここはY軸回転だが、今のところ使わない
    {
        double x3=Pnt[i].z*sin(Y*RAD)+Pnt[i].x*cos(Y*RAD);
        double z3=Pnt[i].z*cos(Y*RAD)-Pnt[i].x*sin(Y*RAD);
        double y3=Pnt[i].y;
  //double x3_=vvv[i].z*sin(Y*RAD)+vvv[i].x*cos(Y*RAD);
        //double z3_=vvv[i].z*cos(Y*RAD)-vvv[i].x*sin(Y*RAD);
        //double y3_=vvv[i].y;
        Pnt[i].x=x3;
        Pnt[i].y=y3;
        Pnt[i].z=z3;
  //vvv[i].x=x3_;
        //vvv[i].y=y3_;
        //vvv[i].z=z3_;
    }
}
void Projection2DAxisFrom3DAxis(HWND hwnd)
{
 HDC hdc = GetDC(hwnd);
    for(int i=0;i<MAXVTX;i++)
    {
        Pnt2[i].x=(Pnt[i].x*D)/(Pnt[i].z-vpz)+(WIDTH/2);
        Pnt2[i].y=-(Pnt[i].y*D)/(Pnt[i].z-vpz)+(HEIGHT/2);
        //PSET(Pnt2[i].x,Pnt2[i].y,0x00ffffff);
  //char str[100];
  //sprintf(str,"%d",i);
  //TextOut(hdc,Pnt2[i].x,Pnt2[i].y,str,strlen(str));
  //TextOut(hdc, 0, i*20, str, strlen(str));
    }
}
void SetPoly(int num,int n1,int n2,int n3,int n4)
{
 Poly[num][0]=n1;//頂点番号を指定
 Poly[num][1]=n2;
 Poly[num][2]=n3;
 Poly[num][3]=n4;
}
void SetPoly(int num,int n1,int n2,int n3)
{
 Poly[num][0]=n1;//頂点番号を指定
 Poly[num][1]=n2;
 Poly[num][2]=n3;
}
void SetPoly(int n1,int n2,int n3)
{
 static int num=0;
 Poly[num][0]=n1;//頂点番号を指定
 Poly[num][1]=n2;
 Poly[num][2]=n3;
 num++;
}
void SetXYZ(int num,double x,double y,double z)
{
    if(num<0 || num>=MAX_XYZ) return;
    Pnt[num].x=x;//頂点座標を指定
    Pnt[num].y=y;
    Pnt[num].z=z;
}
void Init()
{
    SetXYZ(0,-100.0,-100.0,-100.0);//8つの頂点を指定している
    SetXYZ(1, 100.0,-100.0,-100.0);
    SetXYZ(2, 100.0, 100.0,-100.0);
    SetXYZ(3,-100.0, 100.0,-100.0);
    SetXYZ(4,-100.0,-100.0, 100.0);
    SetXYZ(5, 100.0,-100.0, 100.0);
    SetXYZ(6, 100.0, 100.0, 100.0);
    SetXYZ(7,-100.0, 100.0, 100.0);
 SetPoly(0,1,2);
 SetPoly(2,3,0);
 SetPoly(3,4,0);
 SetPoly(3,7,4);
 SetPoly(7,6,5);
 SetPoly(7,5,4);
 SetPoly(6,2,1);
 SetPoly(6,1,5);
 SetPoly(5,1,0);
 SetPoly(0,4,5);
 SetPoly(6,7,3);
 SetPoly(6,3,2);
 MAXVTX = 7;
 SetColor(0,255,255,0);//それぞれのポリゴンの色を設定している
 SetColor(1,255,0,255);
 SetColor(2,0,255,255);
 SetColor(3,255,0,0);
 SetColor(4,0,0,255);
 SetColor(5,255,255,255);
 SetColor(6,255,120,255);
 SetColor(7,0,125,255);
 SetColor(8,255,0,255);
 SetColor(9,0,255,255);
 SetColor(10,255,255,0);
 SetColor(11,0,255,255);
 SetColor(12,255,0,255);
}
BOOL SetClientSize(HWND hWnd, int width, int height)
{
 RECT rw, rc;
 ::GetWindowRect(hWnd, &rw);
 ::GetClientRect(hWnd, &rc);
 int new_width = (rw.right - rw.left) - (rc.right - rc.left) + width;
 int new_height = (rw.bottom - rw.top) - (rc.bottom - rc.top) + height;
 return ::SetWindowPos(hWnd, NULL, 0, 0, new_width, new_height, SWP_NOMOVE | SWP_NOZORDER);
}
inline void PSET(int x, int y, int col)
{
 int R = (col >> 16) & 0xFF;
 int G = (col >> 8) & 0xFF;
 int B = col & 0xFF;
 int address;
 //点を打つ
 if (x >= 0 && y >= 0 && x < WIDTH && y < HEIGHT)
 {
  address = x + (y * WIDTH);
  lpPixel[address] = RGB(B,G,R);
 }
}
void LINE(int x1,int y1,int x2,int y2,int col)
{
    //線分を描画する
    for(int i=0;i<=256;i++)
    {
        int ax=x1*(256-i)+x2*i>>8;
        int ay=y1*(256-i)+y2*i>>8;
        PSET(ax,ay,col);
    }
}
inline void ClearScreen()
{
 //毎回ループの最初で画面を初期化する
 for(int i=0;i<HEIGHT;i++)
 {
  for(int j=0;j<WIDTH;j++)
  {
   PSET(j,i,0x00000000);
   //PSET(i,j,0x00000000);
  }
 }
}
inline void ScanEdge(int x1,int y1,int x2,int y2)
{
 //2次元的なスキャン
    for(int i=0;i<=1024;i++)
    {
        int ax=x1*((1<<10)-i)+x2*i>>10;
        int ay=y1*((1<<10)-i)+y2*i>>10;
        if(ay<0 || ay>=HEIGHT) continue;
  if(minX[ay]>ax) minX[ay]=ax;
  if(maxX[ay]<ax) maxX[ay]=ax;
    }
}
inline void ScanEdge(int x1,int y1,int x2,int y2,int c1,int c2)
{
 int r1=(c1>>16) & 0xFF;
 int g1=(c1>>8) & 0xFF;
 int b1=c1 & 0xFF;
 int r2=(c2>>16) & 0xFF;
 int g2=(c2>>8) & 0xFF;
 int b2=c2 & 0xFF;
    for(int i=0;i<1024;i++)//0.0~1.0を、0~1024に直す
    {
        int ax=(x1*(1024-i)+x2*i)>>10;//線形補間の固定小数点処理化(X成分
        int ay=(y1*(1024-i)+y2*i)>>10;//(固定小数点(Y成分
       // int k=(ay-y1)*100/(y2-y1);//0.0~1.0を0~256に直す
        if(ay<0 || ay>=HEIGHT) return;
  if(minX2[ay]>ax)//minなX(左側の線分)
  {
   minX2[ay]=ax;
   int b=((1024-i)*b1+i*b2)>>10;
   int g=((1024-i)*g1+i*g2)>>10;
   int r=((1024-i)*r1+i*r2)>>10;
   if(r<0) r=0; if(r>255) r=255;
   if(g<0) g=0; if(g>255) g=255;
   if(b<0) b=0; if(b>255) b=255;
   cmin[ay]=RGB(r,g,b);
   PSET(ax,ay,cmin[ay]);
  }
  if(maxX2[ay]<ax)//maxなX(右側の線分)
  {
   maxX2[ay]=ax;
   int b=((1024-i)*b1+i*b2)>>10;
   int g=((1024-i)*g1+i*g2)>>10;
   int r=((1024-i)*r1+i*r2)>>10;
   if(r<0) r=0; if(r>255) r=255;
   if(g<0) g=0; if(g>255) g=255;
   if(b<0) b=0; if(b>255) b=255;
   cmax[ay]=RGB(r,g,b);
   PSET(ax,ay,cmax[ay]);
  }
    }
}
inline void ScanEdge3(int x1,int y1,int x2,int y2,XYZ v1,XYZ v2)
{
    for(int i=0;i<1024;i++)//0.0~1.0を、0~1024に直す
    {
  //double j=(i<<10)/101.0;
        int ax=(x1*(1024-i)+x2*i)/1024;//線形補間の固定小数点処理化(X成分
        int ay=(y1*(1024-i)+y2*i)/1024;//(固定小数点(Y成分
       // int k=(ay-y1)*100/(y2-y1);//0.0~1.0を0~256に直す
        if(ay<0 || ay>=HEIGHT) return;
  if(minX2[ay]>ax)//minなX(左側の線分)
  {
   minX2[ay]=ax;
   vhMin[ay].x=((1024-i)*v1.x+i*v2.x)/1024;
   vhMin[ay].y=((1024-i)*v1.y+i*v2.y)/1024;
   vhMin[ay].z=((1024-i)*v1.z+i*v2.z)/1024;
   Normalize(&vhMin[ay]);
   //double InVx=(ax*D)/(vhMin[ay].z+vpz)+160;
   //double InVy=(ay*D)/(vhMin[ay].z+vpz)+120;
   //LINE(InVx,InVy,ax,ay,RGB(0,0,255));
   //cmin[ay]=RGB(r,g,b);
   //PSET(ax,ay,cmin[ay]);
  }
  if(maxX2[ay]<ax)//maxなX(右側の線分)
  {
   maxX2[ay]=ax;
   vhMax[ay].x=((1024-i)*v1.x+i*v2.x)/1024;
   vhMax[ay].y=((1024-i)*v1.y+i*v2.y)/1024;
   vhMax[ay].z=((1024-i)*v1.z+i*v2.z)/1024;
   Normalize(&vhMax[ay]);
   //cmax[ay]=RGB(r,g,b);
   //PSET(ax,ay,cmax[ay]);
  }
    }
}
inline void TRIANGLE3(int x1,int y1,int x2,int y2,int x3,int y3,XYZ v1,XYZ v2,XYZ v3,XYZ lig)
{
 for(int i=0;i<HEIGHT;i++)
 {
  minX2[i]=65816;
  maxX2[i]=-65816;
  cmin[i]=RGB(0,0,0);
  cmax[i]=RGB(0,0,0);
  vhMin[i].x=0.0f;
  vhMin[i].y=0.0f;
  vhMin[i].z=0.0f;
  vhMax[i].x=0.0f;
  vhMax[i].y=0.0f;
  vhMax[i].z=0.0f;
 }
    ScanEdge3(x1,y1,x2,y2,v1,v2);
    ScanEdge3(x2,y2,x3,y3,v2,v3);
    ScanEdge3(x3,y3,x1,y1,v3,v1);
    for(int y=0;y<HEIGHT;y++)
    {
        if(minX2[y]==65816 || maxX2[y]==-65816) continue;
        for(int x=minX2[y];x<=maxX2[y];x++)
  {
   int j=((x-minX2[y]))*1024/(maxX2[y]-minX2[y]+0.001);
   XYZ vv={0};
   vv.x=(vhMin[y].x*(1024-j)+(vhMax[y].x)*j)/1024;
   vv.y=(vhMin[y].y*(1024-j)+(vhMax[y].y)*j)/1024;
   vv.z=(vhMin[y].z*(1024-j)+(vhMax[y].z)*j)/1024;
   Normalize(&vv);
   /*
   double len=sqrt(vv.x*vv.x+vv.y*vv.y+vv.z*vv.z);
   vv.x/=len;
   vv.y/=len;
   vv.z/=len;
   */
   Normalize(&lig);
   double R=lig.x*vv.x+lig.y*vv.y+lig.z*vv.z;
   double G=lig.x*vv.x+lig.y*vv.y+lig.z*vv.z;
   double B=lig.x*vv.x+lig.y*vv.y+lig.z*vv.z;
   double R2=pow(R,5);
   double G2=pow(G,5);
   double B2=pow(B,5);
   PSET(x,y,RGB(B2*255,G2*255,R2*255));
  }
    }
}
inline void TRIANGLE2(int x1,int y1,int x2,int y2,int x3,int y3,int c1,int c2,int c3)
{
 for(int i=0;i<HEIGHT;i++)
 {
  minX2[i]=65816;
  maxX2[i]=-65816;
  cmin[i]=RGB(0,0,0);
  cmax[i]=RGB(0,0,0);
 }
    ScanEdge(x1,y1,x2,y2,c1,c2);
    ScanEdge(x2,y2,x3,y3,c2,c3);
    ScanEdge(x3,y3,x1,y1,c3,c1);
    for(int y=0;y<HEIGHT;y++)
    {
        if(minX2[y]==65816 || maxX2[y]==-65816) continue;
        for(int x=minX2[y];x<=maxX2[y];x++)
  {
   int r1=cmin[y]>>16 & 0xFF;
   int g1=cmin[y]>>8 & 0xFF;
   int b1=cmin[y] & 0xFF;
   int r2=cmax[y]>>16 & 0xFF;
   int g2=cmax[y]>>8 & 0xFF;
   int b2=cmax[y] & 0xFF;
   int j=((x-minX2[y])<<8)/(maxX2[y]-minX2[y]+1);
   int r=(r1*(256-j)+(r2)*j)>>8;
   int g=(g1*(256-j)+(g2)*j)>>8;
   int b=(b1*(256-j)+(b2)*j)>>8;
   int NewR=r;
   int NewG=g;
   int NewB=b;
   if(NewR<0) NewR=0; if(NewR>255) NewR=255;
   if(NewG<0) NewG=0; if(NewG>255) NewG=255;
   if(NewB<0) NewB=0; if(NewB>255) NewB=255;
            PSET(x,y,RGB(NewR,NewG,NewB));
  }
    }
}
inline void TRIANGLE(int x1,int y1,int x2,int y2,int x3,int y3,int col)
{
 for(int i=0;i<HEIGHT;i++)
 {
  minX[i]=65536;
  maxX[i]=-65536;
 }
    ScanEdge(x1,y1,x2,y2);
    ScanEdge(x1,y1,x3,y3);
    ScanEdge(x2,y2,x3,y3);
    for(int y=0;y<HEIGHT;y++)
    {
        if(minX[y]==65536 || maxX[y]==-65536) continue;
        for(int x=minX[y];x<=maxX[y];x++)
  {
            PSET(x,y,col);
  }
    }
}
void Normalize(XYZ *a)//正規化関Calc
{
   double len=sqrt(a->x*a->x+a->y*a->y+a->z*a->z);
   a->x/=len;
   a->y/=len;
   a->z/=len;
}
double CalcSpecular(XYZ eye,XYZ light,XYZ housen,XYZ n,XYZ buttai)
{
   XYZ RLine;
   XYZ RLight;
   XYZ Ref;
   RLine.x=eye.x-buttai.x;
   RLine.y=eye.y-buttai.y;
   RLine.z=eye.z-buttai.z;//逆視線ベクトルの計算
   Normalize(&RLine);//正規化
   RLight.x=light.x-buttai.x;
   RLight.y=light.y-buttai.y;
   RLight.z=light.z-buttai.z;//逆光線ベクトルの計算
   Normalize(&RLight);//正規化
   double ll=n.x*RLight.x+n.y*RLight.y+n.z*RLight.z;
   Ref.x=ll*2+n.x*RLight.x;
   Ref.x=ll*2+n.y*RLight.y;
   Ref.x=ll*2+n.z*RLight.z;//反射光線ベクトルの計算
   Normalize(&Ref);//正規化
   double a=Ref.x*RLine.x+Ref.y*RLine.y+Ref.z*RLine.z;//反射光線ベクトルと逆視線ベクトルの内積
   return pow(a,30);
}
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInst;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow){
 HWND hwMain;
 MSG msg;
 WNDCLASS wndclass;
 hInst = hInstance;
 wndclass.style = CS_HREDRAW | CS_VREDRAW;
 wndclass.lpfnWndProc = WndProc;
 wndclass.cbClsExtra = 0;
 wndclass.cbWndExtra = 0;
 wndclass.hInstance = hInstance;
 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
 wndclass.lpszMenuName = NULL;
 wndclass.lpszClassName = "CWindow";
 RegisterClass(&wndclass);
 hwMain = CreateWindow("CWindow", "Phong Shading(is Testing)",
          WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
          WIDTH*2+22,HEIGHT*2+36+6, NULL, NULL, hInstance, NULL);
    SetClientSize(hwMain,320*2,240*2);//ウィンドウサイズ丁度良いサイズに調整してくれる
 /* ウインドウを表示 */
 ShowWindow(hwMain, iCmdShow);
 UpdateWindow(hwMain);
 /* メッセージループ */
 while(GetMessage(&msg, NULL, 0, 0)) {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
 return msg.wParam;
}
inline void LINE2COL(int x1,int y1,int x2,int y2,int COL,int COL2)
{
 //線を描くのと左か右かを判断する関数
 int NewX,NewY;
 for(int j=0;j<256;j++)
 {
  NewX=x1*(256-j)+x2*j>>8;
  NewY=y1*(256-j)+y2*j>>8;
  int R1,R2,G1,G2,B1,B2;
  R1=(COL>>16) & 0xFF;
  G1=(COL>>8) & 0xFF;
  B1=(COL) & 0xFF;
  R2=(COL2>>16) & 0xFF;
  G2=(COL2>>8) & 0xFF;
  B2=(COL2) & 0xFF;
  int R=R1*(256-j)+R2*j>>8;
  int G=G1*(256-j)+G2*j>>8;
  int B=B1*(256-j)+B2*j>>8;
  PSET(NewX,NewY,RGB(R,G,B));
  if(min_[(int)NewY]>NewX){
   min_[(int)NewY]=NewX;
   cmin[(int)NewY]=RGB(R,G,B);
  }
  if(max_[(int)NewY]<NewX){
   max_[(int)NewY]=NewX;
   cmax[(int)NewY]=RGB(R,G,B);
  }
 }
}
int min_Y(int y1,int y2,int y3)
{
 if(y1<y2 && y1<y3) return y1;
 if(y2<y1 && y2<y3) return y2;
 if(y3<y1 && y3<y2) return y3;
}
int max_Y(int y1,int y2,int y3)
{
 if(y1>y2 && y1>y3) return y1;
 if(y2>y1 && y2>y3) return y2;
 if(y3>y1 && y3>y2) return y3;
}
inline void GouraudShade(int x1,int y1,int x2,int y2,int x3,int y3,int C1,int C2,int C3)
{
 //入れ忘れ(笑)
 for(int i=0;i<SCREENHEIGHT;i++)
 {
  min_[i]=65816;
  max_[i]=-65816;
  cmin[i]=RGB(0,0,0);
  cmax[i]=RGB(0,0,0);
 }
 //LINE2COL(x1,y1,x2,y2,C1,C2);
 //LINE2COL(x2,y2,x3,y3,C2,C3);
 //LINE2COL(x1,y1,x3,y3,C1,C3);
 ScanEdge(x1,y1,x2,y2,C1,C2);
 ScanEdge(x2,y2,x3,y3,C2,C3);
 ScanEdge(x3,y3,x1,y1,C3,C1);
 for(int Y=0;Y<HEIGHT;Y++)
 {
  if(min_[Y]==65816 || max_[Y]==-65816) continue;
  int R1=(cmin[Y]>>16) & 0xFF;
  int G1=(cmin[Y]>>8) & 0xFF;
  int B1=(cmin[Y]) & 0xFF;
  int R2=(cmax[Y]>>16) & 0xFF;
  int G2=(cmax[Y]>>8) & 0xFF;
  int B2=(cmax[Y]) & 0xFF;
  LINE2COL(min_[Y],Y,max_[Y],Y,RGB(R1,G1,B1),RGB(R2,G2,B2));
 }
}
void LoadOBJFile(char filename[10000],HWND hwnd)
{
 static int flag=0;
 FILE *fp;
 fp=fopen(filename,"r");
 if(fp==NULL)
 {
  MessageBox(NULL,"ファイルがありません。","OK?",MB_OK);
  SelectObject(hdcBMP, hBMPOLD);
  DeleteObject(hdcBMP);
  DeleteObject(hBMP);
  PostQuitMessage(0);
  return;
 }
 int i=0;
 int j=0;
 while(fgets(FileStr[i],50,fp)!=NULL)
 {
  j=0;
  //以下の内容が通用しないのでテキストエディタ(最悪Windowsのメモ帳でも可)
  //で空白を,(カンマ)に変換する必要がある、
  //通用した、改行の処理を忘れていただけのようだ。これで、objファイルは大丈夫のようだ
  while(FileStr[i][j])
  {
   if(FileStr[i][j]==' ') FileStr[i][j]=',';
   ++j;
   if(FileStr[i][j]=='\n') ++i;
  }
 }
 LastLine=i;//最後の行数を保存する
 char opecode[10000]={0};
 double XF,YF,ZF;
 int TriNum1,TriNum2,TriNum3,TriNum4;
 int k=0;
 for(i=0;i<LastLine;i++)
 {
   opecode[0]=FileStr[i][0];
   //CameraPos.D=535.0f;
   //CameraPos.Z=-810.0f;
   //PSET(400,300,GetColor(0,0,255));
   if(opecode[0]=='v')
   {
    sscanf(FileStr[i],"%c,%lf,%lf,%lf",
    opecode,&XF,&YF,&ZF);
    SetXYZ(k,XF*SCALE,YF*SCALE,ZF*SCALE);
    Projection2DAxisFrom3DAxis(hwnd);
    //i=0;
    ++k;
    MAXVTX=k;
   }
   if(opecode[0]=='f')
   {
    sscanf(FileStr[i],"%c,%d,%d,%d,%d",
    opecode,&TriNum1,&TriNum2,&TriNum3,&TriNum4);
    if(flag==0)
    {
     j=0;
     flag=1;
    }
    SetPoly(j,(int)TriNum1-1,(int)TriNum2-1,(int)TriNum3-1,(int)TriNum4-1);
    Projection2DAxisFrom3DAxis(hwnd);
    ++j;
    MAXPOL=j;
   }
 }
}
XYZ CalcCross(XYZ a,XYZ b,XYZ c)
{
 XYZ d={0.0f};
 XYZ a2,b2;
   a2.x=a.x-b.x;
   a2.y=a.y-b.y;
   a2.z=a.z-b.z;
   b2.x=a.x-c.x;
   b2.y=a.y-c.y;
   b2.z=a.z-c.z;
   Normalize(&a2);
   //double len=sqrt(a2.x*a2.x+a2.y*a2.y+a2.z*a2.z+0.1);
   //a2.x/=len;
   //a2.y/=len;
   //a2.z/=len;
   Normalize(&b2);
   //double len2=sqrt(b2.x*b2.x+b2.y*b2.y+b2.z*b2.z+0.1);
   //b2.x/=len2;
   //b2.y/=len2;
   //b2.z/=len2;
            //23-32 31-13 12-21
            //aY*bZ-aZ*bY aZ*bX-aX*bZ aX*bY-aY*bX
   d.x=a2.y*b2.z-a2.z*b2.y;
   d.y=a2.z*b2.x-a2.x*b2.z;
   d.z=a2.x*b2.y-a2.y*b2.x;
  return d;
}
double CalcDotProduct(XYZ a, XYZ b)
{
 return a.x * b.x + a.y * b.y + a.z * b.z;
}
int JisakuRGB(int R, int G, int B)
{
 if (R > 255) R = 255;
 if (G > 255) G = 255;
 if (B > 255) B = 255;
 if (R < 0) R = 0;
 if (G < 0) G = 0;
 if (B < 0) B = 0;
 return R << 16 | G << 8 << B;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
    HDC hdc;
    PAINTSTRUCT ps;
 static int DrawMode = 0;
 static int prevSpace = 0;
    switch (iMsg) {
    case WM_TIMER:
        {
            if(GetAsyncKeyState(VK_ESCAPE)<0)
                SendMessage(hwnd,WM_DESTROY,NULL,NULL);
            double X=0.0f;
            double Y=0.0f;
            double Z=0.0f;
            //Z+=0.1f;
            //Y+=0.1f;
            if(GetAsyncKeyState(VK_RIGHT)<0) Y=-2.5f;
            else if(GetAsyncKeyState(VK_LEFT)<0) Y=2.5f;
            else Y=0.0f;
            if(GetAsyncKeyState(VK_DOWN)<0) X=-2.5f;
            else if(GetAsyncKeyState(VK_UP)<0) X=2.5f;
            else X=0.0f;
   if (GetAsyncKeyState(VK_SPACE) < 0 && !prevSpace)
    DrawMode = (DrawMode + 1) & 3;
   prevSpace = GetAsyncKeyState(VK_SPACE) < 0;
            Rotate(X,Y,0);
            static int X1=0,X2=0;
            int n=8;
            InvalidateRect(hwnd,NULL,NULL);
        }
        return 0;
    case WM_CREATE:
       //MyOutputDebugString("起動しました。");
        //Init();//3次元座標を代入
 // SetXYZ(0,-100,-100,0);
 // SetXYZ(1,-100,100,0);
 // SetXYZ(2,100,100,0);
 // SetXYZ(3,100,-100,0);
 /*SetXYZ(0,-100.0,-100.0,-100.0);//8つの頂点を指定している
    SetXYZ(1, 100.0,-100.0,-100.0);
    SetXYZ(2, 100.0, 100.0,-100.0);
    SetXYZ(3,-100.0, 100.0,-100.0);
  SetPoly( 0,1,2);
  SetPoly(2,3,0);
*/
  //Projection2DAxisFrom3DAxis(hwnd);
   /*
   0 3
   ********
   *++++++*
   *++++++*
   *++++++*
   ********
   1 2
   */
        //LoadOBJFile("./womanbody.obj",hwnd);
        //LoadOBJFile("./heimen.obj",hwnd);//cube.obj
        //LoadOBJFile("./DO-NATSU.obj",hwnd);
  LoadOBJFile("./do-natsu.obj",hwnd);
        SetTimer(hwnd,100,2,NULL);
        /* BITMAPINFOをゼロクリア */
        ZeroMemory(&biInfo, sizeof(BITMAPINFO));
        /* BITMAPINFO設定 */
        biInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        biInfo.bmiHeader.biWidth = WIDTH;
        biInfo.bmiHeader.biHeight = -HEIGHT;
        biInfo.bmiHeader.biPlanes = 1;
        biInfo.bmiHeader.biBitCount = 32;
        biInfo.bmiHeader.biCompression = BI_RGB;
        /* ウインドウのDCを取得 */
        hdc = GetDC(hwnd);
        /* biInfoの形式でDIBSectionを作成 */
        hBMP =CreateDIBSection(hdc, &biInfo, DIB_RGB_COLORS, (LPVOID*)(&lpPixel), NULL, 0);
        /* DIBSection用のメモリDCを作成 */
        hdcBMP = CreateCompatibleDC(hdc);
        /* メモリDCにDIBSectionを選択 */
        hBMPOLD = (HBITMAP)SelectObject(hdcBMP, hBMP);
        /* 不要になったウインドウのDCを解放 */
        ReleaseDC(hwnd, hdc);
        return 0;
    case WM_PAINT:
        {
  int i;
        hdc = BeginPaint(hwnd, &ps);
        ClearScreen();//画面を消す
        //PSET(320,240,0x00ff0000);//点を打つ
        //LINE(320,240,640,380,0x00ff0000);
  TRIANGLE2(80,50,10,140,260,80,RGB(255,0,0),RGB(0,255,0),RGB(0,0,255));
        Projection2DAxisFrom3DAxis(hwnd);//透視投影
  //PSET(160, 120, 0x00ff0000);
        //PSET(320,240,0x00FFFFFF);
        XYZ vvv[1000];//全ての頂点の法線をクリアする
        for(i=0;i<MAXVTX;i++)
        {
            vvv[i].x=0.0f;//Clear
            vvv[i].y=0.0f;//Clear
            vvv[i].z=0.0f;//Clear
   vvv[i].count =0;
        }
        XYZ a[1000];
        XYZ b[1000];
        //XYZ n3;
        //頂点ベクトルは求まった(はず...)から、頂点カラーを面にある全ての頂点で求める
  //XYZ vpx=200,vpy=-120,vpz=100;
  for (i = 0; i < MAXVTX; i++)
  {
   int i1 = Poly[i][0];
   int i2 = Poly[i][1];
   int i3 = Poly[i][2];
   int i4 = Poly[i][3];
   XYZ n = CalcCross(Pnt[i1], Pnt[i2], Pnt[i3]);
   //外積を行った
   Normalize(&n);
   //正規化を行った
   XYZ n2 = CalcCross(Pnt[i3], Pnt[i4], Pnt[i2]);
   //外積を行った
   Normalize(&n2);
   //正規化を行った
   vvv[i1].x += n.x;
   vvv[i1].y += n.y;
   vvv[i1].z += n.z;
   vvv[i2].x += n.x;
   vvv[i2].y += n.y;
   vvv[i2].z += n.z;
   vvv[i3].x += n.x;
   vvv[i3].y += n.y;
   vvv[i3].z += n.z;
   vvv[i4].x += n2.x;
   vvv[i4].y += n2.y;
   vvv[i4].z += n2.z;
  }
  for (i = 0; i < MAXVTX; i++)
  {
   Normalize(&vvv[i]);
   //vvv[i].x/=vvv[i].count ;
   //vvv[i].y/=vvv[i].count ;
   //vvv[i].z/=vvv[i].count ;
  }
        //XYZ vpx=200,vpy=-120,vpz=100;
        for(i=0;i<MAXVTX;i+=1)
        {
            int i1=Poly[i][0];
            int i2=Poly[i][1];
            int i3=Poly[i][2];
   int i4 = Poly[i][3];
            XYZ n=CalcCross(Pnt[i1],Pnt[i2],Pnt[i3]);
   Normalize(&n);
            XYZ light={0,0,-5};
            double lenlight=sqrt((double)light.x*light.x+light.y*light.y+light.z*light.z+0.1);
            light.x/=lenlight;
            light.y/=lenlight;
            light.z/=lenlight;
   double spe1 = vvv[i1].x * light.x + vvv[i1].y * light.y + vvv[i1].z * light.z;
   double spe2 = vvv[i2].x * light.x + vvv[i2].y * light.y + vvv[i2].z * light.z;
   double spe3 = vvv[i3].x * light.x + vvv[i3].y * light.y + vvv[i3].z * light.z;
   double spe4 = vvv[i4].x * light.x + vvv[i4].y * light.y + vvv[i4].z * light.z;
            double ViewCos;
   //-------------------------------------------------------------------------
            double v7=ViewCos=(light.x*n.x+light.y*n.y+light.z*n.z);
   double p=pow(ViewCos, 50);
   if (p > 255) p = 255;
   //-------------------------------------------------------------------------
            //視線ベクトルと面ごとの法線ベクトルの内積
   //ViewCos<0
   if (ViewCos > 0)
   {
    if (DrawMode == 1) {
     TRIANGLE(Pnt2[Poly[i][1]].x, Pnt2[Poly[i][1]].y,
      Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      RGB(v7 * 255, v7 * 255, v7 * 255)
      //vvv[i1],vvv[i2],vvv[i3],light
     );
     TRIANGLE(Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      Pnt2[Poly[i][3]].x, Pnt2[Poly[i][3]].y,
      RGB(v7 * 255, v7 * 255, v7 * 255)
      //JisakuRGB(p * 255 * 50 + 30, p * 201 + 1 + 30, p * 201 + 1 + 30)
      //vvv[i1],vvv[i2],vvv[i3],light
     );
    }
    else if (DrawMode == 2)
    {
     //TRIANGLE(Pnt2[Poly[i][1]].x, Pnt2[Poly[i][1]].y,
     // Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
     // Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
     // //vvv[i1],vvv[i2],vvv[i3],light
     //);
     //TRIANGLE(Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
     // Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
     // Pnt2[Poly[i][3]].x, Pnt2[Poly[i][3]].y,
     // RGB(v7 * 255, v7 * 255, v7 * 255)
      double p = pow(ViewCos, 30);
     double pgb = ViewCos * 1.0f;
     //double R2=pow(spe1*1,55);
     TRIANGLE2(Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      Pnt2[Poly[i][1]].x, Pnt2[Poly[i][1]].y,
      Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      //RGB(ViewCos*255,ViewCos*255,ViewCos*255)
      RGB(spe1*255, spe1 * 255, spe1 * 255),
      RGB(spe2 *255, spe2 * 255, spe2 * 255),
      RGB(spe3*255, spe3 * 255, spe3 * 255)
     );
     TRIANGLE2(Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      Pnt2[Poly[i][3]].x, Pnt2[Poly[i][3]].y,
      Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      //RGB(ViewCos*255,ViewCos*255,ViewCos*255)
      RGB(spe3 * 255, spe3 * 255, spe3 * 255),
      RGB(spe4 * 255, spe4 * 255, spe4 * 255),
      RGB(spe1 * 255, spe1 * 255, spe1 * 255)
     );
     //TRIANGLE(Pnt2[0].x, Pnt2[0].y, Pnt2[1].x, Pnt2[1].y, Pnt2[17].x, Pnt2[17].y, RGB(0, 0, 255));
    }
    else if (DrawMode == 3) {
     TRIANGLE3(Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      Pnt2[Poly[i][1]].x, Pnt2[Poly[i][1]].y,
      Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      vvv[i1], vvv[i2], vvv[i3], light
     );
     TRIANGLE3(Pnt2[Poly[i][2]].x, Pnt2[Poly[i][2]].y,
      Pnt2[Poly[i][3]].x, Pnt2[Poly[i][3]].y,
      Pnt2[Poly[i][0]].x, Pnt2[Poly[i][0]].y,
      vvv[i3], vvv[i4], vvv[i1], light
     );
    }
   }
        }
        //反時計回りの座標軸
        //三角形を表示する
            //DrawTextureMapping(240,0,0,120,240,0);
            //FillGraRect(0,0,320,20,255,0,0,0,255,0);
  /*
  TClipSize a5,b5;
  a5.width =320;
  a5.height=240;
  b5.width =320;
  b5.height =240;
  TClipBltInfo c;
   c.dx=0;
   c.dy=0;
   c.sh=240;
   c.sw=320;
   c.sx=0;
   c.sy=0;
  if(!ClipBltInfo(&a5,&b5,&c)) return FALSE;
  */
        /* DIBSectionをDIBとして描画 */
            StretchDIBits(hdc, 0, 0, WIDTH*2, HEIGHT*2,
                0, 0, WIDTH, HEIGHT, lpPixel, &biInfo,
                DIB_RGB_COLORS,SRCCOPY);
            CalcFPS(hdc);
            EndPaint(hwnd, &ps);
            DeleteObject(SelectObject(hdc , GetStockObject(WHITE_BRUSH)));
        }
        return 0;
    case WM_DESTROY: /* ウインドウ破棄時 */
        SelectObject(hdcBMP, hBMPOLD);
        DeleteObject(hdcBMP);
        DeleteObject(hBMP);
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, iMsg, wParam, lParam);
}

おまけ:
レイトレーシングのサンプルプログラムです。
球と球の当たり判定を利用したレイトレーシングなので
もしかしたら精度が悪いかもしれません。




サービス数40万件のスキルマーケット、あなたにぴったりのサービスを探す