#define MAX_CUBES 4
static HDC hdc, hSceneDC;
int mg3dSceneTestProc(HWND hWnd, int msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case MSG_CREATE:
{
/* ...... */
/* 得到窗口的DC句柄 */
hdc = GetClientDC(hWnd);
/* 为场景建立Memory DC。
mG3d组件的多边形的渲染等工作都是在Memory DC中完成的,
当在Memory DC中完成了一帧的渲染后,利用BitBlt函数
将Memory DC中的画面拷贝到窗口的DC中加以显示。
下面建立的是一个16位色的Memory DC且尺寸与窗口的大小一致
*/
hSceneDC = CreateMemDC(SCREEN_W, SCREEN_H, 16,
MEMDC_FLAG_SWSURFACE, 0, 0, 0, 0);
/* 建立场景,因为每个立方体由6个面组成,每个面又由4个顶点组成,
一共有64个正方体,所以场景中最多顶点数目为(第一个参数):
24 * MAX_CUBES * MAX_CUBES * MAX_CUBES = 6*4*4*4*4;
因为每个多边行有六个面,所以场景中最多多边形数目为:
6 * MAX_CUBES * MAX_CUBES * MAX_CUBES = 6*4*4*4
*/
mg3dCreateScene(24 * MAX_CUBES * MAX_CUBES * MAX_CUBES,
6 * MAX_CUBES * MAX_CUBES * MAX_CUBES);
/* 设置视口 */
mg3dSetProjectionViewport(0, 0, SCREEN_W, SCREEN_H);
/* ...... */
break;
}
}
case MSG_KEYDOWN:
{
if (wParam != SCANCODE_CURSORBLOCKLEFT) {
break;
}
/* ...... */
/* 在一个循环中完成多边形的生成和渲染*/
for ( ; ; ) {
/* 每渲染一帧之前,应当清空Memory DC
中的内容 */
SetBrushColor(hSceneDC, PIXEL_black);
FillBox(hSceneDC, 0, 0, WNDWIDTH, WNDHEIGHT);
/* 每渲染一帧之前需要初始化场景一次 */
mg3dClearScene(hSceneDC);
/* 根据旋转角度的增量生成新的旋转变换矩阵 */
mg3dGetRotMatrixF(&matrix2, rx, ry, 0);
mg3dGetRotMatrixF(&matrix3, 0, rot, 0);
/* 64个正方体在空间中的排列方式为:X,Y,Z轴方向上各有4个正方体,共计64个。
下面的循环针对每一个正方体来计算它的平移运动的偏移量,生成每个正方体最终的运顶变换矩阵。
在这个例子中,所有正方体共享相同的旋转矩阵,但是每个正方体有自己独特的平移矩阵。
每次循环都是针对一个正方体,对于同一个正方体上的顶点,它们的变换矩阵是一样的。
draw_cube函数的主要作用是将一个正方体的六个面加入多边行渲染列表,此时并不真正的渲染
多边形。
*/
for (k = MAX_CUBES - 1; k >= 0; k--) {
for (j = 0; j < MAX_CUBES; j++) {
for (i = 0; i < MAX_CUBES; i++) {
/* 得到每个正方体的平移矩阵 */
mg3dGetTranslationMatrixF(&matrix1, j*40-MAX_CUBES*20+20,
i*40-MAX_CUBES*20+20, tz+k*40);
/* 将平移矩阵和上面两个旋转矩阵做乘法,
得到最终的变换矩阵,注意矩阵乘法的相乘顺序 */
mg3dMatrixMulF(&matrix2, &matrix1, &matrix);
mg3dMatrixMulF(&matrix, &matrix3, &matrix);
draw_cube(&matrix, 6);
}
}
}
/* 渲染一幅场景,此时场景中所有的多边形将被真正的“画”在Memory DC上 */
mg3dRenderScene();
/* 把场景Memory DC中的内容拷贝到窗口DC中,窗口将显示这一帧 */
BitBlt(hSceneDC, 0, 0, WNDWIDTH, WNDHEIGHT, hdc, 0, 0, 0);
/* 重新计算旋转角度,位移等增量 */
tz -= 2;
if (!tz) tz = 40;
rx += 4;
ry += 4;
rot += inc;
if ((rot >= 25) || (rot <= -25)) inc = -inc;
/* ...... */
}
break;
}
void draw_cube(mg3dMatrixf *matrix, int num_poly)
{
int i, j, nv;
/* out数组是提供给mg3dClipF函数运行时需要的临时缓冲区 */
int out[12];
/* 正方体一共有6个面,循环每次完成一个面的运算 */
for (i = 0; i < num_poly; i++) {
/* 每个面都有4个顶点,对每个顶点应用刚才求得的变换矩阵 */
for (j = 0; j < 4; j++) {
v[j] = vertex[cube[i].v[j]];
mg3dApplyMatrixF(matrix, v[j].x, v[j].y, v[j].z,
&v[j].x, &v[j].y, &v[j].z);
}
/* 对正方体的每个面做3d裁剪,MG3D_POLYTYPE_GCOL是渲染类型,
0.1, 1000.表明裁剪的边界;4表明被裁剪的多边形初始有4个顶点,
pv是保存多边形顶点的数组的指针,pvout指向是裁剪后的多边形顶点数组
pvtmp,out都是为mg3dClipF提供的临时缓冲区。
值得注意的是,由于多边形裁剪后的顶点数可能大于其原有顶点数,所以
提供的保存运算结果的数组和临时缓冲区应该尽量的大。
mg3dClipF的返回值就是裁剪后多边形的顶点数。
*/
nv = mg3dClipF(hSceneDC, MG3D_POLYTYPE_GCOL,
0.1, 1000., 4,
(const mg3dVpf**)pv, pvout,
pvtmp, out);
if (nv) {
/* 把裁剪后的各个顶点投影到二维屏幕上 */
for (j = 0; j < nv; j++) {
mg3dPerspProjectF(vout[j].x, vout[j].y, vout[j].z,
&(vout[j].x), &(vout[j].y));
}
/* 把这个多边行加入到待渲染多边形链表中 */
if (mg3dPolygonZNormalF(&vout[0], &vout[1], &vout[2]) > 0) {
mg3dScenePolygonF(MG3D_POLYTYPE_GCOL, hTextureDC, nv, pvout);
}
}
}
}/* ...... */ /* 释放DC,销毁场景,释放资源 */ ReleaseDC(hdc); ReleaseDC(hSceneDC); mg3dDestroyScene();