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です。
#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:フォンシェーディング
画素単位の頂点ベクトルを求めるアルゴリズムです。
光の当たり方に関しての画質はポリゴン(非レイトレーシング)
の中では一番良い(はず)です。
#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);
}
おまけ:
レイトレーシングのサンプルプログラムです。
球と球の当たり判定を利用したレイトレーシングなので
もしかしたら精度が悪いかもしれません。