1,把所有的点存储为1*2矩阵
typedef struct MATRIX1X2_TYP
{
float M[2];
}MATRIX1X2, * MATRIX1X2_PTR;
M = |X Y|
,2把所有变换矩阵采用3*2矩阵
typedef struct MATRIX3X2_TYP
{
float M[3][2];
}MATRIX3X2, * MATRIX3X2_PTR;
分为平移,缩放,旋转3种
(1) 平移
Mt = | 1 0 0 |
| 0 1 0 |
|dx dy 1 |
(2)缩放
|sx 0 0 |
MS = |0 sy 0 |
|0 0 0|
(3)旋转
|cosA sinA 0|
Mr = |-sinA cosA 0|
| 0 0 1|
平移(矩阵方式)
下面这个函数用来写平移实在是没效率,不过正如作者所说,是个教学目的。不过非常熟悉矩阵了。
int Translate_Polygon2D_Mat( POLYGON2D_PTR poly, int dx, int dy )
{
if( ! poly )
{
return ( 0 );
}
MATRIX3X2 mt;
Mat_Init_3X2( & mt, 1, 0, 0, 1, dx, dy );
MATRIX1X2 p0 = { poly->x0, poly->y0 };
MATRIX1X2 p1 = { 0, 0 };
Mat_Mul1X2_3X2( & p0, & mt, & p1 );
poly->x0 = p1.M[0];
poly->y0 = p1.M[1];
return ( 1 );
}
旋转,也是矩阵方式,确实锻炼基础啊。
int Rotate_Polygon2D_Mat(POLYGON2D_PTR poly, int theta)
{
// this function rotates the local coordinates of the polygon
// test for valid pointer
if (!poly)
return(0);
// test for negative rotation angle
if (theta < 0)
theta+=360;
MATRIX3X2 mr; // used to hold rotation transform matrix
// initialize the matrix with translation values dx dy
Mat_Init_3X2(&mr,cos_look[theta],sin_look[theta],
-sin_look[theta],cos_look[theta],
0, 0);
// loop and rotate each point, very crude, no lookup!!!
for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++)
{
// create a 1x2 matrix to do the transform
MATRIX1X2 p0 = {poly->vlist[curr_vert].x, poly->vlist[curr_vert].y};
MATRIX1X2 p1 = {0,0}; // this will hold result
// now rotate via a matrix multiply
Mat_Mul1X2_3X2(&p0, &mr, &p1);
// now copy the result back into vertex
poly->vlist[curr_vert].x = p1.M[0];
poly->vlist[curr_vert].y = p1.M[1];
} // end for curr_vert
// return success
return(1);
} // end Rotate_Polygon2D_Mat
放缩
int Scale_Polygon2D_Mat(POLYGON2D_PTR poly, float sx, float sy);
{
if ( !poly )
{
return ( 0 );
}
MATRIX3X2 ms;
Mat_Init_3X2( & ms, sx, 0, 0, sy, 0, 0 );
for ( int curr_vert = 0; curr_vert < poly->num_verts; curr_vert ++ )
{
MATRIX1X2 p0 = { poly->vlist[curr_vert].x, poly->vlist[curr_vert].y };
MATRIX1X2 p1 = { 0, 0 };
Mat_Mul1X2_3X2( & p0, & mr, & p1 );
poly->vlist[curr_vert].x= p1.M[0];
poly->vlist[curr_vert].y= p1.M[1];
}
return ( 1 );
}
矩阵[1][2] * [3][2]
int Mat_Mul1X2_3X2( MATRIX1X2_PTR ma, MATRIX3X2_PTR mb, MATRIX1X2_PTR mprod )
{
for( int col = 0; col < 2; col ++ )
{
float sum = 0;
for ( int index = 0; index < 2; index++ )
{
sum += ( ma->M[index] * mb->M[index][col];
}
sum += mb->M[index][col];
mprod->M[col] = sum;
}
return ( 1 );
}
初始化:
int Mat_Init_3X2( MATRIX3X2_PTR ma, float m00, float m01, float m10, float m11, float m20, float m21 )
{
ma->M[0][0] = m00;
ma->M[0][1] = m01;
ma->M[1][0] = m10;
ma->M[1][1] = m11;
ma->M[2][0] = m20;
ma->M[2][1] = m21;
return ( 1 );
}
在game_main()中,
以前是
// test for scale
if (KEYDOWN('A')) // scale up
Scale_Polygon2D(&asteroid, 1.1, 1.1);
else
if (KEYDOWN('S')) // scale down
Scale_Polygon2D(&asteroid, 0.9, 0.9);
现在是矩阵形式
// test for scale
if (KEYDOWN('A')) // scale up
Scale_Polygon2D_Mat(&ship, 1.1, 1.1);
else
if (KEYDOWN('S')) // scale down
Scale_Polygon2D_Mat(&ship, 0.9, 0.9);
再加上旋转和平移
if ( KEYDOWN( 'Z'))
{
Rotate_Polygon2D_Mat( & ship, -5 );
}
else
if ( KEYDOWN( 'X'))
{
Rotate_Polygon2D_Mat( & ship, 5 );
}
if ( KEYDOWN( VK_RIGHT))
{
Translate_Polygon2D_Mat( & ship,5, 0 );
}
else
if ( KEYDOWN( VK_LEFT))
{
Translate_Polygon2D_Mat( & ship,-5, 0 );
}
if ( KEYDOWN( VK_UP))
{
Translate_Polygon2D_Mat( & ship,0, -5 );
}
else
if ( KEYDOWN( VK_DOWN))
{
Translate_Polygon2D_Mat( & ship,0, 5 );
}
在Game_Init()中,
开始时
srand( GetTickCount())
然后改定
LPPALETTEENTRY color;
color->peRed = 255;
color->peGreen = 0;
color->peBlue = 0;
color->peFlags = PC_NOCOLLAPSE;
ddraw->Set_Palette_Entry( 1, color );
LPPALETTEENTRY color2;
color2->peRed = 0;
color2->peGreen = 255;
color2->peBlue = 0;
color2->peFlags = PC_NOCOLLAPSE;
ddraw->Set_Palette_Entry( 2, color2 );
LPPALETTEENTRY color3;
color3->peRed = 0;
color3->peGreen = 0;
color3->peBlue = 255;
color3->peFlags = PC_NOCOLLAPSE;
ddraw->Set_Palette_Entry( 3, color3 );
// define points of asteroid
VERTEX2DF ship_vertices[24] =
{
1, 11,
2, 8,
1, 7,
1, -1,
3,-1,
3,-2,
11,-3,
11,-6,
3,-7,
2,-8,
1,-8,
1,-7,
-1,-7,
-1,-8,
-2,-8,
-3,-7,
-11,-6,
-11,-3,
-3,-2,
-3,-1,
-1,-1,
-1,7,-2,8,-1,11
};
// initialize asteroid
ship.state = 1; // turn it on
ship.num_verts = 24;
ship.x0 = SCREEN_WIDTH/2; // position it
ship.y0 = SCREEN_HEIGHT/2;
ship.xv = 0;
ship.yv = 0;
ship.color = 2; // white
ship.vlist = new VERTEX2DF [ship.num_verts];
for (int index = 0; index < ship.num_verts; index++)
ship.vlist[index] = ship_vertices[index];
结果如下图:
封装一下。
成员函数
int DDRAW_Interface::Translate_Polygon2D_Mat( POLYGON2D_PTR poly, int dx, int dy )
{
if( ! poly )
{
return ( 0 );
}
MATRIX3X2 mt;
Mat_Init_3X2( & mt, 1, 0, 0, 1, dx, dy );
MATRIX1X2 p0 = { poly->x0, poly->y0 };
MATRIX1X2 p1 = { 0, 0 };
Mat_Mul1X2_3X2( & p0, & mt, & p1 );
poly->x0 = p1.M[0];
poly->y0 = p1.M[1];
return ( 1 );
}
int DDRAW_Interface::Rotate_Polygon2D_Mat(POLYGON2D_PTR poly, int theta)
{
// this function rotates the local coordinates of the polygon
// test for valid pointer
if (!poly)
return(0);
// test for negative rotation angle
if (theta < 0)
theta+=360;
MATRIX3X2 mr; // used to hold rotation transform matrix
// initialize the matrix with translation values dx dy
Mat_Init_3X2(&mr,cos_look[theta],sin_look[theta],
-sin_look[theta],cos_look[theta],
0, 0);
// loop and rotate each point, very crude, no lookup!!!
for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++)
{
// create a 1x2 matrix to do the transform
MATRIX1X2 p0 = {poly->vlist[curr_vert].x, poly->vlist[curr_vert].y};
MATRIX1X2 p1 = {0,0}; // this will hold result
// now rotate via a matrix multiply
Mat_Mul1X2_3X2(&p0, &mr, &p1);
// now copy the result back into vertex
poly->vlist[curr_vert].x = p1.M[0];
poly->vlist[curr_vert].y = p1.M[1];
} // end for curr_vert
// return success
return(1);
} // end Rotate_Polygon2D_Mat
int DDRAW_Interface::Scale_Polygon2D_Mat(POLYGON2D_PTR poly, float sx, float sy)
{
if ( !poly )
{
return ( 0 );
}
MATRIX3X2 ms;
Mat_Init_3X2( & ms, sx, 0, 0, sy, 0, 0 );
for ( int curr_vert = 0; curr_vert < poly->num_verts; curr_vert ++ )
{
MATRIX1X2 p0 = { poly->vlist[curr_vert].x, poly->vlist[curr_vert].y };
MATRIX1X2 p1 = { 0, 0 };
Mat_Mul1X2_3X2( & p0, & ms, & p1 );
poly->vlist[curr_vert].x= p1.M[0];
poly->vlist[curr_vert].y= p1.M[1];
}
return ( 1 );
}
int DDRAW_Interface::Mat_Mul1X2_3X2( MATRIX1X2_PTR ma, MATRIX3X2_PTR mb, MATRIX1X2_PTR mprod )
{
int index;
for( int col = 0; col < 2; col ++ )
{
float sum = 0;
for ( index = 0; index < 2; index++ )
{
sum += ( ma->M[index] * mb->M[index][col];
}
sum += mb->M[index][col];
mprod->M[col] = sum;
}
return ( 1 );
}
int DDRAW_Interface::Mat_Init_3X2( MATRIX3X2_PTR ma, float m00, float m01, float m10, float m11, float m20, float m21 )
{
ma->M[0][0] = m00;
ma->M[0][1] = m01;
ma->M[1][0] = m10;
ma->M[1][1] = m11;
ma->M[2][0] = m20;
ma->M[2][1] = m21;
return ( 1 );
}
Game_init()不变
Game_main()改为
ddraw->Draw_Polygon2D(&ship, ddraw->getbackbuffer(), ddraw->getbacklpitch());
// test for scale
if (KEYDOWN('A')) // scale up
ddraw->Scale_Polygon2D_Mat(&ship, 1.1, 1.1);
else
if (KEYDOWN('S')) // scale down
ddraw->Scale_Polygon2D_Mat(&ship, 0.9, 0.9);
if ( KEYDOWN( 'Z'))
{
ddraw->Rotate_Polygon2D_Mat( & ship, -5 );
}
else
if ( KEYDOWN( 'X'))
{
ddraw->Rotate_Polygon2D_Mat( & ship, 5 );
}
if ( KEYDOWN( VK_RIGHT))
{
ddraw->Translate_Polygon2D_Mat( & ship,5, 0 );
}
else
if ( KEYDOWN( VK_LEFT))
{
ddraw->Translate_Polygon2D_Mat( & ship,-5, 0 );
}
if ( KEYDOWN( VK_UP))
{
ddraw->Translate_Polygon2D_Mat( & ship,0, -5 );
}
else
if ( KEYDOWN( VK_DOWN))
{
ddraw->Translate_Polygon2D_Mat( & ship,0, 5 );
}
// rotate the polygon by 5 degrees
ddraw->Rotate_Polygon2D(&ship, 5);
结果OK
,根据T3DLIB进行,将矩阵为数组和结构体的联合体
typedef struct MATRIX3X2_TYP
{
union
{
float M[3][2];
struct
{
float M00, M01;
float M10, M11;
float M20, M21;
};
};
}MATRIX3X2, * MATRIX3X2_PTR;
typedef struct MATRIX1X2_TYP
{
union
{
float M[2];
struct
{
float M00, float M01;
};
};
}MATRIX1X2, * MATRIX1X2_PTR;
补充个
int DDRAW_Interface::Draw_Polygon2D16( POLYGON2D_PTR poly, UCHAR * vbuffer, int lpitch )
{
int index = 0;
if( poly->state )
{
for(index = 0; index < poly->num_verts - 1; index ++ )
{
Draw_Clip_Line16( poly->vlist[index].x + poly->x0,
poly->vlist[index].y + poly->y0,
poly->vlist[index+1].x + poly->x0,
poly->vlist[index+1].y + poly->y0,
poly->color,
vbuffer, lpitch );
}
Draw_Clip_Line16( poly->vlist[0].x + poly->x0,
poly->vlist[0].y + poly->y0,
poly->vlist[index].x + poly->x0,
poly->vlist[index].y + poly->y0,
poly->color,
vbuffer, lpitch );
return ( 1 );
}
else
return ( 0 );
}
在构造函数中,
m_dwWidth = SCREEN_WIDTH;
m_dwHeight = SCREEN_HEIGHT;
m_dwBPP = SCREEN_BPP;
而不是以前的0.
我的思路这里有个问题,就是切换区域实际上应该在成员变量里,因为每个窗口未必一样,应该是个变量,
所以设置成员变量。
int m_min_clip_x;
int m_min_clip_y;
int m_max_clip_x;
int m_max_clip_y;
构造函数上初始化
m_max_clip_x = SCREEN_WIDTH - 1;
m_max_clip_y = SCREEN_HEIGHT - 1;
m_min_clip_x = 0;
m_min_clip_y = 0;
相应地,在ddraw_init()中改为
m_min_clip_x = 0;
m_max_clip_x = width - 1;
m_min_clip_y = 0;
m_max_clip_y = height - 1;
RECT screen_rect = { 0, 0, width, height };
m_lpddclipper = DDraw_Attach_Clipper( m_lpddsback, 1, & screen_rect );
以前遗漏了一个
int DDRAW_Interface::Set_Palette( LPPALETTEENTRY set_palette )
{
memcpy( palette, set_palette, MAX_COLORS_PALETTE * sizeof( PALETTEENTRY ) );
m_lpddpal->SetEntries( 0, 0, MAX_COLORS_PALETTE, palette );
return ( 1 );
}
再一运行发现有问题,改为以前的。
m_min_clip_x = 0;
m_max_clip_x = width - 1;
m_min_clip_y = 0;
m_max_clip_y = height - 1;
RECT screen_rect = { 0, 0, width -1, height - 1 };
m_lpddclipper = DDraw_Attach_Clipper( m_lpddsback, 1, & screen_rect );
恢复正常,看来尽信书不如无书。
因篇幅问题不能全部显示,请点此查看更多更全内容