BilliardView.cpp
资源名称:taiqiu.rar [点击查看]
上传用户:owen_mei
上传日期:2022-08-09
资源大小:2263k
文件大小:32k
源码类别:
OpenGL
开发平台:
Visual C++
- // BilliardView.cpp : implementation of the CBilliardView class
- //
- #include "stdafx.h"
- #include "Billiard.h"
- #include "BilliardDoc.h"
- #include "BilliardView.h"
- #include "model.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- /////////////////////////////////////////////////////////////////////////////
- // CBilliardView
- IMPLEMENT_DYNCREATE(CBilliardView, CView)
- BEGIN_MESSAGE_MAP(CBilliardView, CView)
- //{{AFX_MSG_MAP(CBilliardView)
- ON_WM_CREATE()
- ON_WM_DESTROY()
- ON_WM_SIZE()
- ON_WM_TIMER()
- ON_WM_LBUTTONDOWN()
- ON_WM_LBUTTONUP()
- ON_WM_MOUSEMOVE()
- ON_WM_RBUTTONDOWN()
- ON_WM_RBUTTONUP()
- ON_WM_KEYDOWN()
- //}}AFX_MSG_MAP
- // Standard printing commands
- ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
- ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
- ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
- END_MESSAGE_MAP()
- /////////////////////////////////////////////////////////////////////////////
- // CBilliardView construction/destruction
- CBilliardView::CBilliardView()
- {
- // TODO: add construction code here
- g_Dragging = FALSE; // 鼠标的初始状态不是拖动状态
- g_DrawingStick = FALSE; // 球杆在初始时不随场景一起绘制
- g_LastTime = 0;
- g_SimRunning = TRUE; // 初始时即进入游戏
- g_TimeIterations = 10;
- g_UseFixedTimeStep = FALSE; // 不使用固定的时间步长
- g_MaxTimeStep = 0.01f;
- g_CollisionRootFinding = FALSE;
- g_UseDamping = TRUE; // 初始时应用阻尼
- g_UseFriction = TRUE; // 初始时应用摩擦
- g_CueHitBall = FALSE; // 初始时球杆没有击中球
- g_BallInPlay = FALSE; // 初始时没有球在运动
- }
- CBilliardView::~CBilliardView()
- {
- }
- BOOL CBilliardView::PreCreateWindow(CREATESTRUCT& cs)
- {
- // TODO: Modify the Window class or styles here by modifying
- // the CREATESTRUCT cs
- ////////////////////////////////////////////////////////////////
- //设置窗口类型
- cs.style |=WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
- ////////////////////////////////////////////////////////////////
- return CView::PreCreateWindow(cs);
- }
- /////////////////////////////////////////////////////////////////////////////
- // CBilliardView drawing
- void CBilliardView::OnDraw(CDC* pDC)
- {
- CBilliardDoc* pDoc = GetDocument();
- ASSERT_VALID(pDoc);
- // TODO: add draw code for native data here
- //////////////////////////////////////////////////////////////////
- RenderWorld(); //渲染场景
- //////////////////////////////////////////////////////////////////
- }
- /////////////////////////////////////////////////////////////////////////////
- // CBilliardView printing
- BOOL CBilliardView::OnPreparePrinting(CPrintInfo* pInfo)
- {
- // default preparation
- return DoPreparePrinting(pInfo);
- }
- void CBilliardView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
- {
- // TODO: add extra initialization before printing
- }
- void CBilliardView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
- {
- // TODO: add cleanup after printing
- }
- /////////////////////////////////////////////////////////////////////////////
- // CBilliardView diagnostics
- #ifdef _DEBUG
- void CBilliardView::AssertValid() const
- {
- CView::AssertValid();
- }
- void CBilliardView::Dump(CDumpContext& dc) const
- {
- CView::Dump(dc);
- }
- CBilliardDoc* CBilliardView::GetDocument() // non-debug version is inline
- {
- ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CBilliardDoc)));
- return (CBilliardDoc*)m_pDocument;
- }
- #endif //_DEBUG
- /////////////////////////////////////////////////////////////////////////////
- // CBilliardView message handlers
- int CBilliardView::OnCreate(LPCREATESTRUCT lpCreateStruct)
- {
- if (CView::OnCreate(lpCreateStruct) == -1)
- return -1;
- // TODO: Add your specialized creation code here
- //////////////////////////////////////////////////////////////////
- //初始化OpenGL和设置定时器
- m_pDC = new CClientDC(this);
- SetTimer(1, 20, NULL);
- InitializeOpenGL(m_pDC);
- //////////////////////////////////////////////////////////////////
- SetupViewRC();
- g_LastTime = GetTime();
- InitRender();
- if(!InitGame())
- return -1;
- return 0;
- }
- void CBilliardView::OnDestroy()
- {
- CView::OnDestroy();
- // TODO: Add your message handler code here
- /////////////////////////////////////////////////////////////////
- //删除调色板和渲染上下文、定时器
- ::wglMakeCurrent(0,0);
- ::wglDeleteContext( m_hRC);
- if (m_hPalette)
- DeleteObject(m_hPalette);
- if ( m_pDC )
- {
- delete m_pDC;
- }
- KillTimer(1);
- /////////////////////////////////////////////////////////////////
- }
- void CBilliardView::OnSize(UINT nType, int cx, int cy)
- {
- CView::OnSize(nType, cx, cy);
- // TODO: Add your message handler code here
- if(cy == 0) // 避免被0除
- cy = 1;
- double dAspect = (double)cx/(double)cy;
- // 设置视口
- glViewport(0, 0, cx, cy);
- // 设置投影矩阵
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- // 设置投影变换
- gluPerspective(60.0, dAspect,0.2f, 2000);
- // 设置模型矩阵
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- }
- void CBilliardView::OnTimer(UINT nIDEvent)
- {
- // TODO: Add your message handler code here and/or call default
- /////////////////////////////////////////////////////////////////
- //添加定时器响应函数和场景更新函数
- Invalidate(FALSE);
- /////////////////////////////////////////////////////////////////
- CView::OnTimer(nIDEvent);
- }
- /////////////////////////////////////////////////////////////////////
- // 设置逻辑调色板
- //////////////////////////////////////////////////////////////////////
- void CBilliardView::SetLogicalPalette(void)
- {
- struct
- {
- WORD Version;
- WORD NumberOfEntries;
- PALETTEENTRY aEntries[256];
- } logicalPalette = { 0x300, 256 };
- BYTE reds[] = {0, 36, 72, 109, 145, 182, 218, 255};
- BYTE greens[] = {0, 36, 72, 109, 145, 182, 218, 255};
- BYTE blues[] = {0, 85, 170, 255};
- for (int colorNum=0; colorNum<256; ++colorNum)
- {
- logicalPalette.aEntries[colorNum].peRed =
- reds[colorNum & 0x07];
- logicalPalette.aEntries[colorNum].peGreen =
- greens[(colorNum >> 0x03) & 0x07];
- logicalPalette.aEntries[colorNum].peBlue =
- blues[(colorNum >> 0x06) & 0x03];
- logicalPalette.aEntries[colorNum].peFlags = 0;
- }
- m_hPalette = CreatePalette ((LOGPALETTE*)&logicalPalette);
- }
- //////////////////////////////////////////////////////////
- // 初始化openGL场景
- //////////////////////////////////////////////////////////
- BOOL CBilliardView::InitializeOpenGL(CDC* pDC)
- {
- m_pDC = pDC;
- SetupPixelFormat();
- //生成绘制描述表
- m_hRC = ::wglCreateContext(m_pDC->GetSafeHdc());
- //置当前绘制描述表
- ::wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC);
- return TRUE;
- }
- //////////////////////////////////////////////////////////
- // 设置像素格式
- //////////////////////////////////////////////////////////
- BOOL CBilliardView::SetupPixelFormat()
- {
- PIXELFORMATDESCRIPTOR pfd = {
- sizeof(PIXELFORMATDESCRIPTOR), // pfd结构的大小
- 1, // 版本号
- PFD_DRAW_TO_WINDOW | // 支持在窗口中绘图
- PFD_SUPPORT_OPENGL | // 支持 OpenGL
- PFD_DOUBLEBUFFER, // 双缓存模式
- PFD_TYPE_RGBA, // RGBA 颜色模式
- 24, // 24 位颜色深度
- 0, 0, 0, 0, 0, 0, // 忽略颜色位
- 0, // 没有非透明度缓存
- 0, // 忽略移位位
- 0, // 无累加缓存
- 0, 0, 0, 0, // 忽略累加位
- 32, // 32 位深度缓存
- 0, // 无模板缓存
- 0, // 无辅助缓存
- PFD_MAIN_PLANE, // 主层
- 0, // 保留
- 0, 0, 0 // 忽略层,可见性和损毁掩模
- };
- int pixelformat;
- pixelformat = ::ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);//选择像素格式
- ::SetPixelFormat(m_pDC->GetSafeHdc(), pixelformat, &pfd); //设置像素格式
- if(pfd.dwFlags & PFD_NEED_PALETTE)
- SetLogicalPalette(); //设置逻辑调色板
- return TRUE;
- }
- //////////////////////////////////////////////////////////
- // 场景绘制与渲染
- //////////////////////////////////////////////////////////
- BOOL CBilliardView::RenderWorld()
- {
- float Time;
- float DeltaTime;
- if (g_UseFixedTimeStep) // 如果使用固定步长
- Time = g_LastTime + (g_MaxTimeStep * g_TimeIterations);
- else
- Time = GetTime();
- if (g_SimRunning)
- {
- while(g_LastTime < Time)
- {
- DeltaTime = Time - g_LastTime;
- if(DeltaTime > g_MaxTimeStep)
- {
- DeltaTime = g_MaxTimeStep;
- }
- Simulate(DeltaTime,g_SimRunning);
- g_LastTime += DeltaTime;
- }
- g_LastTime = Time;
- }
- else
- {
- DeltaTime = 0;
- Simulate(DeltaTime,g_SimRunning);
- }
- ////////////////////////////////////////////////////////////////
- // 清除颜色缓存和深度缓存
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glPushMatrix();
- g_CueStick.yaw = -g_POV.rot.y; // 设置球杆始终位于视场中心
- // 设置摄像机平移
- glTranslatef(-g_POV.trans.x, -g_POV.trans.y, -g_POV.trans.z);
- // 设置摄像机旋转
- glRotatef(g_POV.rot.z, 0.0f, 0.0f, 1.0f);
- glRotatef(g_POV.rot.x, 1.0f, 0.0f, 0.0f);
- glRotatef(g_POV.rot.y, 0.0f, 1.0f, 0.0f);
- glTranslatef(-g_CueStick.pos.x, -g_CueStick.pos.y, -g_CueStick.pos.z);
- RenderScene(); // 绘制静止的场景
- RenderCueAndBalls(); // 绘制球杆和球
- glPopMatrix();
- ::SwapBuffers(m_pDC->GetSafeHdc()); //交互缓冲区
- return TRUE;
- }
- void CBilliardView::OnLButtonDown(UINT nFlags, CPoint point)
- {
- // TODO: Add your message handler code here and/or call default
- g_Dragging = TRUE; // 按下鼠标左键,将鼠标设置为拖动状态
- g_LastYaw = g_POV.rot.y; // 保存摄像机绕Y轴旋转的位置
- g_LastPitch = g_POV.rot.x; // 保存摄像机绕X轴旋转的位置
- g_MouseHitX = point.x; // 鼠标单击的X坐标
- g_MouseHitY = point.y; // 鼠标单击的Y坐标
- // 设置球杆的位置
- g_CueStick.pos.x = g_CurrentSys->pos.x;
- g_CueStick.pos.z = g_CurrentSys->pos.z;
- SetCapture();
- CView::OnLButtonDown(nFlags, point);
- }
- void CBilliardView::OnLButtonUp(UINT nFlags, CPoint point)
- {
- // TODO: Add your message handler code here and/or call default
- g_Dragging = FALSE; // 释放鼠标左键,解除鼠标的拖动状态
- ReleaseCapture();
- CView::OnLButtonUp(nFlags, point);
- }
- void CBilliardView::OnMouseMove(UINT nFlags, CPoint point)
- {
- // TODO: Add your message handler code here and/or call default
- tx = point.x; // 记下当前鼠标的X坐标
- ty = point.y; // 记下当前鼠标的Y坐标
- if (g_Dragging) // 当鼠标处于拖动状态
- {
- if (tx != g_MouseHitX)
- {
- // 摄像机绕Y轴旋转
- g_POV.rot.y = g_LastYaw + (float)(tx - g_MouseHitX);
- Invalidate(FALSE);;
- }
- if (ty != g_MouseHitY)
- {
- // 摄像机绕X轴旋转
- g_POV.rot.x = g_LastPitch + (float)(ty - g_MouseHitY);
- if (g_POV.rot.x < 0.0f)
- g_POV.rot.x = 0.0f;
- if (g_POV.rot.x > 90.0f)
- g_POV.rot.x = 90.0f;
- Invalidate(FALSE);;
- }
- }
- // 如果球杆处于绘制状态(即拖动是鼠标右键),并且球的运动没有结束
- if (g_DrawingStick && !g_BallInPlay)
- {
- if (ty != g_MouseHitY)
- {
- g_CueStick.draw = g_LastDraw + ((float)(ty - g_MouseHitY) * 0.1f);
- // 向后移动球杆
- if (g_LastDraw < g_CueStick.draw)
- {
- g_CueStick.old_draw = g_CueStick.draw;
- g_CueStick.drawtime = GetTime();
- }
- // 如果球杆接触到球,则击中球
- else if (g_CueStick.draw < 0.0f)
- {
- g_CueHitBall = TRUE; // 设置球击中标志为TRUE
- magnitude = -CUE_STICK_FORCE * ((g_CueStick.old_draw - g_CueStick.draw) / (GetTime() - g_CueStick.drawtime));
- g_CueForce.x = magnitude * sin(DEGTORAD(g_CueStick.yaw));
- g_CueForce.z = magnitude * cos(DEGTORAD(g_CueStick.yaw));
- g_CueStick.draw = 0.2f;
- g_BallInPlay = TRUE; // 击中球后,球开始运动
- g_DrawingStick = FALSE; // 不绘制球杆
- }
- Invalidate(FALSE);;
- }
- }
- CView::OnMouseMove(nFlags, point);
- }
- void CBilliardView::OnRButtonDown(UINT nFlags, CPoint point)
- {
- // TODO: Add your message handler code here and/or call default
- g_DrawingStick = TRUE; // 绘制球杆
- g_LastDraw = g_CueStick.draw; // 保存球杆与球之间的距离
- g_CueStick.old_draw = g_CueStick.draw; // 保存球杆与球之间的距离
- g_MouseHitX = point.x; // 鼠标单击的X坐标
- g_MouseHitY = point.y; // 鼠标单击的Y坐标
- // 重新设置球杆的位置
- g_CueStick.pos.x = g_CurrentSys->pos.x;
- g_CueStick.pos.z = g_CurrentSys->pos.z;
- SetCapture();
- CView::OnRButtonDown(nFlags, point);
- }
- void CBilliardView::OnRButtonUp(UINT nFlags, CPoint point)
- {
- // TODO: Add your message handler code here and/or call default
- g_DrawingStick = FALSE; // 不绘制球杆
- ReleaseCapture();
- CView::OnRButtonUp(nFlags, point);
- }
- void CBilliardView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
- {
- // TODO: Add your message handler code here and/or call default
- switch(nChar)
- {
- case VK_UP:
- {
- if (g_POV.rot.x > 0.0f)
- g_POV.rot.x -= 1.0; // 绕X轴负方向旋转
- Invalidate(FALSE);;
- break;
- }
- case VK_DOWN:
- {
- if (g_POV.rot.x < 90.0f)
- g_POV.rot.x += 1.0; // 绕X轴正方向旋转
- Invalidate(FALSE);;
- break;
- }
- case VK_LEFT:
- {
- g_POV.rot.y += 1.0; // 绕Y轴正方向旋转
- Invalidate(FALSE);;
- break;
- }
- case VK_RIGHT:
- {
- g_POV.rot.y -= 1.0; // 绕Y轴负方向旋转
- Invalidate(FALSE);;
- break;
- }
- case VK_PRIOR: // 场景放大
- {
- if (g_POV.trans.z > 1.0f)
- // 摄像机向z轴的负方向平移
- g_POV.trans.z -= 1.0;
- Invalidate(FALSE);;
- break;
- }
- case VK_NEXT: // 场景缩小
- {
- if (g_POV.trans.z < 9.0f)
- // 摄像机向z轴方向平移
- g_POV.trans.z += 1.0;
- Invalidate(FALSE);;
- break;
- }
- }
- CView::OnKeyDown(nChar, nRepCnt, nFlags);
- }
- // 下面的函数的功能是对游戏进行初始化
- BOOL CBilliardView::InitGame(void)
- {
- g_CueStick.draw = g_CueStick.old_draw = 0.2f;
- g_CueStick.yaw = 0.0f;
- g_CueStick.pos.x = -4.0f;
- g_CueStick.pos.y = TABLE_POSITION;
- g_CueStick.pos.z = 0.0f;
- g_Kd = 0.02f; // 阻尼因子
- g_Kr_Bumper = 0.8f; // 球与边界之间碰撞的恢复系数
- g_Kr_Ball = 0.2f; // 球与球之间碰撞的恢复系数
- g_Csf = 0.2f; // 缺省的静摩擦
- g_Ckf = 0.1f; // 缺省的动摩擦
- MAKEVECTOR(g_Gravity, 0.0f, -32.0f, 0.0f)
- g_IntegratorType = EULER_INTEGRATOR;
- g_CollisionRootFinding = FALSE; // ONLY SET WHEN FINDING A COLLISION
- g_ContactCnt = 0;
- SetupBalls();
- g_CurrentSys = g_GameSys[0];
- g_TargetSys = g_GameSys[1];
- g_CollisionPlaneCnt = 4;
- // 左边的碰撞平面
- MAKEVECTOR(g_CollisionPlane[0].normal,1.0f, 0.0f, 0.0f)
- g_CollisionPlane[0].d = LEFT_BUMPER;
- // 右边的碰撞平面
- MAKEVECTOR(g_CollisionPlane[1].normal,-1.0f, 0.0f, 0.0f)
- g_CollisionPlane[1].d = RIGHT_BUMPER;
- // 上边的碰撞平面
- MAKEVECTOR(g_CollisionPlane[2].normal, 0.0f, 0.0f, -1.0f)
- g_CollisionPlane[2].d = TOP_BUMPER;
- // 下边的碰撞平面
- MAKEVECTOR(g_CollisionPlane[3].normal, 0.0f, 0.0f, 1.0f)
- g_CollisionPlane[3].d = BOTTOM_BUMPER;
- return TRUE;
- }
- void CBilliardView::InitRender(void)
- {
- int loop;
- // 初始化摄像机的位置
- g_POV.trans.x = 0.0f;
- g_POV.trans.y = 0.0f;
- g_POV.trans.z = 8.0f;
- g_POV.rot.x = 20.0f;
- g_POV.rot.y = 90.0f;
- g_POV.rot.z = 0.0f;
- // 定义白球的显示列表
- glNewList(OGL_WBALL_DLIST,GL_COMPILE);
- // 定义数据序列
- glInterleavedArrays(WBALLFORMAT,0,(GLvoid *)&WBALLMODEL);
- glBegin(GL_TRIANGLES);
- for (loop = 0; loop < WBALLPOLYCNT * 3; loop++)
- {
- glArrayElement(loop);
- }
- glEnd();
- glEndList();
- // 定义黄球的显示列表
- glNewList(OGL_YBALL_DLIST,GL_COMPILE);
- // 定义数据序列
- glInterleavedArrays(YBALLFORMAT,0,(GLvoid *)&YBALLMODEL);
- glBegin(GL_TRIANGLES);
- for (loop = 0; loop < YBALLPOLYCNT * 3; loop++)
- {
- glArrayElement(loop);
- }
- glEnd();
- glEndList();
- // 定义球杆的显示列表
- glNewList(OGL_CUE_DLIST,GL_COMPILE);
- // 定义数据序列
- glInterleavedArrays(CUEFORMAT,0,(GLvoid *)&CUEMODEL);
- glBegin(GL_TRIANGLES);
- for (loop = 0; loop < CUEPOLYCNT * 3; loop++)
- {
- glArrayElement(loop);
- }
- glEnd();
- glEndList();
- LoadTextures();
- LoadSceneFile("Pool.ros"); // 装入场景数据
- }
- // 下面的函数的功能是将所有的TGA图像数据读入到纹理中
- void CBilliardView::LoadTextures()
- {
- GLubyte *rgb;
- char texName[80];
- tTGAHeader_s tgaHeader;
- HANDLE specHandle;
- WIN32_FIND_DATA fileData;
- int rv;
- g_TextureCnt = 0;
- sprintf(texName,"%s*.tga",ART_PATH);
- if ((specHandle=FindFirstFile(texName,&fileData))!= INVALID_HANDLE_VALUE)
- {
- do
- {
- sprintf(g_TexPool[g_TextureCnt].map,"%s%s",ART_PATH,fileData.cFileName);
- glGenTextures(1,&g_TexPool[g_TextureCnt].glTex);
- rgb = m_LoadTGA.LoadTGAFile( g_TexPool[g_TextureCnt].map,&tgaHeader);
- if (rgb == NULL)
- {
- MessageBox("Unable to Open File...",g_TexPool[g_TextureCnt].map,MB_OK);
- g_TexPool[g_TextureCnt].glTex = 0;
- return;
- }
- glBindTexture(GL_TEXTURE_2D, g_TexPool[g_TextureCnt].glTex);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- // 定义2D纹理像素格式
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4); /* Force 4-byte alignment */
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
- glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
- glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
- if (tgaHeader.d_pixel_size == 32)
- {
- glTexImage2D(GL_TEXTURE_2D, 0, 4, tgaHeader.d_width, tgaHeader.d_height, 0,
- GL_RGBA , GL_UNSIGNED_BYTE, rgb);
- rv = gluBuild2DMipmaps( GL_TEXTURE_2D, 4, tgaHeader.d_width, tgaHeader.d_height,
- GL_RGBA, GL_UNSIGNED_BYTE, rgb );
- }
- else
- {
- glTexImage2D(GL_TEXTURE_2D, 0, 3, tgaHeader.d_width, tgaHeader.d_height, 0,
- GL_RGB, GL_UNSIGNED_BYTE, rgb);
- rv = gluBuild2DMipmaps( GL_TEXTURE_2D, 3, tgaHeader.d_width, tgaHeader.d_height, GL_RGB,
- GL_UNSIGNED_BYTE, rgb );
- }
- // 释放位图和RGB图像数据
- free(rgb);
- g_TextureCnt++;
- }while (FindNextFile(specHandle,&fileData));
- FindClose(specHandle);
- }
- }
- void CBilliardView::LoadSceneFile(char *filename)
- {
- FILE *fp;
- char tempstr[80];
- t_Visual *visual;
- fp = fopen(filename,"rb");
- if (fp != NULL)
- {
- fread(tempstr,1,4,fp);
- if (strncmp(tempstr,"ROSC",4)!= 0)
- {
- MessageBox("Not a Valid Data File","Load File", MB_OK|MB_ICONEXCLAMATION);
- return;
- }
- visual = &g_Scene;
- fread(&visual->vertexCnt,sizeof(long),1,fp);
- visual->vertex = (tVector *)malloc(sizeof(tVector) * visual->vertexCnt);
- fread(visual->vertex,sizeof(tVector),visual->vertexCnt,fp);
- fread(&visual->triCnt,sizeof(long),1,fp);
- visual->tri = (tPrimPoly *)malloc(sizeof(tPrimPoly) * (visual->triCnt));
- fread(visual->tri,sizeof(tPrimPoly),visual->triCnt,fp);
- fread(&visual->quadCnt,sizeof(long),1,fp);
- visual->quad = (tPrimPoly *)malloc(sizeof(tPrimPoly) * (visual->quadCnt));
- fread(visual->quad,sizeof(tPrimPoly),visual->quadCnt,fp);
- fclose(fp);
- }
- }
- // 设置OpenGL绘制环境
- void CBilliardView::SetupViewRC(void)
- {
- // 设置黑色背景
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
- glCullFace(GL_BACK);
- glFrontFace(GL_CCW);
- glEnable(GL_CULL_FACE);
- // 使用深度测试
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_TEXTURE_2D);
- // 无光照
- glDisable(GL_LIGHTING);
- glDisable(GL_LIGHT0);
- glPolygonMode(GL_FRONT,GL_FILL);
- glDepthFunc(GL_LESS);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- }
- void CBilliardView::RenderCueAndBalls()
- {
- // 绘制白球
- glPushMatrix();
- glTranslatef(g_CurrentSys[0].pos.x,g_CurrentSys[0].pos.y,g_CurrentSys[0].pos.z);
- glCallList(OGL_WBALL_DLIST);
- glPopMatrix();
- // 绘制黄球
- glPushMatrix();
- glTranslatef(g_CurrentSys[1].pos.x,g_CurrentSys[1].pos.y,g_CurrentSys[1].pos.z);
- glCallList(OGL_YBALL_DLIST);
- glPopMatrix();
- // 绘制球杆
- glPushMatrix();
- // 球杆的位置
- glTranslatef(g_CueStick.pos.x,g_CueStick.pos.y,g_CueStick.pos.z);
- // 绕Y轴旋转
- glRotatef(g_CueStick.yaw, 0.0f, 1.0f, 0.0f);
- // 绕X轴旋转一个固定角度,即略向上抬
- glRotatef(-5.0f, 1.0f, 0.0f, 0.0f);
- // 击球时向后移动球杆
- glTranslatef(0,0,g_CueStick.draw);
- glCallList(OGL_CUE_DLIST);
- glPopMatrix();
- }
- void CBilliardView::RenderScene()
- {
- int loop,loop2;
- t_Visual *visual;
- tPrimPoly *poly;
- glEnable(GL_TEXTURE_2D);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- visual = &g_Scene;
- for (loop2 = 0; loop2 < g_TextureCnt; loop2++)
- {
- poly = visual->quad;
- glBindTexture(GL_TEXTURE_2D, g_TexPool[loop2].glTex);
- for (loop = 0; loop < visual->quadCnt; loop++)
- {
- if ((poly->type & POLY_TEXTURED) > 0 && poly->TexNdx1 == (uint)loop2)
- {
- glBegin(GL_QUADS);
- glTexCoord2fv((float *)&poly->t1[0]);
- glColor3ubv((unsigned char *)&poly->color[0]);
- glVertex3fv((float *)&visual->vertex[poly->index[0]]);
- glTexCoord2fv((float *)&poly->t1[1]);
- glColor3ubv((unsigned char *)&poly->color[1]);
- glVertex3fv((float *)&visual->vertex[poly->index[1]]);
- glTexCoord2fv((float *)&poly->t1[2]);
- glColor3ubv((unsigned char *)&poly->color[2]);
- glVertex3fv((float *)&visual->vertex[poly->index[2]]);
- glTexCoord2fv((float *)&poly->t1[3]);
- glColor3ubv((unsigned char *)&poly->color[3]);
- glVertex3fv((float *)&visual->vertex[poly->index[3]]);
- glEnd();
- }
- poly++;
- }
- poly = visual->tri;
- for (loop = 0; loop < visual->triCnt; loop++)
- {
- if ((poly->type & POLY_TEXTURED) > 0 && poly->TexNdx1 == (uint)loop2)
- {
- glBegin(GL_TRIANGLES);
- glTexCoord2fv((float *)&poly->t1[0]);
- glColor3ubv((unsigned char *)&poly->color[0]);
- glVertex3fv((float *)&visual->vertex[poly->index[0]]);
- glTexCoord2fv((float *)&poly->t1[1]);
- glColor3ubv((unsigned char *)&poly->color[1]);
- glVertex3fv((float *)&visual->vertex[poly->index[1]]);
- glTexCoord2fv((float *)&poly->t1[2]);
- glColor3ubv((unsigned char *)&poly->color[2]);
- glVertex3fv((float *)&visual->vertex[poly->index[2]]);
- glEnd();
- }
- poly++;
- }
- }
- glDisable(GL_TEXTURE_2D);
- }
- void CBilliardView::SetupBalls()
- {
- int loop, loop2;
- for (loop = 0; loop < SYSTEM_COUNT; loop++)
- {
- for (loop2 = 0; loop2 < BALL_COUNT; loop2++)
- {
- switch (loop2)
- {
- // 球1是球杆需要击中的球
- case 0:
- MAKEVECTOR(g_GameSys[loop][loop2].pos,-4.0f, TABLE_POSITION, 0.0f)
- break;
- case 1:
- MAKEVECTOR(g_GameSys[loop][loop2].pos,4.0f, TABLE_POSITION, 0.0f)
- break;
- }
- MAKEVECTOR(g_GameSys[loop][loop2].v,0.0f, 0.0f, 0.0f)
- MAKEVECTOR(g_GameSys[loop][loop2].f,0.0f, 0.0f, 0.0f)
- g_GameSys[loop][loop2].oneOverM = 1.0f / 0.34f;
- MAKEVECTOR(g_GameSys[loop][loop2].angMom,0.0f, 0.0f, 0.0f)
- MAKEVECTOR(g_GameSys[loop][loop2].torque,0.0f, 0.0f, 0.0f)
- // 四元数清零
- MAKEVECTOR(g_GameSys[loop][loop2].orientation,0.0f, 0.0f, 0.0f)
- g_GameSys[loop][loop2].orientation.w = 1.0f;
- g_GameSys[loop][loop2].flags = 0;
- g_GameSys[loop][loop2].flags = 0;
- }
- }
- }
- #define STATIC_THRESHOLD 0.03f // 速度的阈值,用于判断使用何种摩擦
- void CBilliardView::ComputeForces( t_Ball *system)
- {
- int loop;
- t_Ball *curBall;
- tVector contactN;
- float FdotN,VdotN,Vmag;
- tVector Vn,Vt;
- curBall = system;
- for (loop = 0; loop < BALL_COUNT; loop++)
- {
- MAKEVECTOR(curBall->f,0.0f,0.0f,0.0f) // 清除力
- MAKEVECTOR(curBall->torque,0.0f, 0.0f, 0.0f) // 清除力矩
- if (g_UseDamping) // 如果用户定义阻尼
- {
- curBall->f.x += (-g_Kd * curBall->v.x);
- curBall->f.y += (-g_Kd * curBall->v.y);
- curBall->f.z += (-g_Kd * curBall->v.z);
- }
- else // 否则使用缺省阻尼
- {
- curBall->f.x += (-DEFAULT_DAMPING * curBall->v.x);
- curBall->f.y += (-DEFAULT_DAMPING * curBall->v.y);
- curBall->f.z += (-DEFAULT_DAMPING * curBall->v.z);
- }
- // 下面处理球与桌面之间的摩擦问题
- if (g_UseFriction)
- {
- // 计算正压力,即重力
- FdotN = g_Gravity.y / curBall->oneOverM;
- // 计算垂直于法向平面的速度
- MAKEVECTOR(contactN,0.0f, 1.0f, 0.0f)
- VdotN = m_MathDefs.DotProduct(&contactN,&curBall->v);
- m_MathDefs.ScaleVector(&contactN, VdotN, &Vn);
- m_MathDefs.VectorDifference(&curBall->v, &Vn, &Vt);
- Vmag = m_MathDefs.VectorSquaredLength(&Vt);
- // 判断速度是否大于阈值
- if (Vmag > STATIC_THRESHOLD) // 大于阈值,使用动摩擦模型
- {
- m_MathDefs.NormalizeVector(&Vt);
- m_MathDefs.ScaleVector(&Vt, (FdotN * g_Ckf), &Vt);
- m_MathDefs.VectorSum(&curBall->f,&Vt,&curBall->f);
- }
- else // 小于阈值,使用静摩擦模型
- {
- Vmag = Vmag / STATIC_THRESHOLD;
- m_MathDefs.NormalizeVector(&Vt);
- m_MathDefs.ScaleVector(&Vt, (FdotN * g_Csf * Vmag), &Vt); // Scale Friction by Velocity
- m_MathDefs.VectorSum(&curBall->f,&Vt,&curBall->f);
- if (loop == 0)
- {
- g_BallInPlay = FALSE;
- }
- }
- }
- curBall++;
- }
- // 用户是否定义了球杆撞击球的力
- if (g_CueHitBall)
- {
- m_MathDefs.VectorSum(&system[0].f,&g_CueForce,&system[0].f);
- }
- }
- void CBilliardView::IntegrateSysOverTime(t_Ball *initial,t_Ball *source, t_Ball *target, float deltaTime)
- {
- int loop;
- float deltaTimeMass;
- for (loop = 0; loop < BALL_COUNT; loop++)
- {
- deltaTimeMass = deltaTime * initial->oneOverM;
- // 获得新的速度
- target->v.x = initial->v.x + (source->f.x * deltaTimeMass);
- target->v.y = initial->v.y + (source->f.y * deltaTimeMass);
- target->v.z = initial->v.z + (source->f.z * deltaTimeMass);
- target->oneOverM = initial->oneOverM;
- // 获得新的位置坐标
- target->pos.x = initial->pos.x + (deltaTime * source->v.x);
- target->pos.y = initial->pos.y + (deltaTime * source->v.y);
- target->pos.z = initial->pos.z + (deltaTime * source->v.z);
- initial++;
- source++;
- target++;
- }
- }
- // 欧拉积分
- void CBilliardView::EulerIntegrate( float DeltaTime)
- {
- IntegrateSysOverTime(g_CurrentSys,g_CurrentSys, g_TargetSys,DeltaTime);
- }
- // 中点方法
- void CBilliardView::MidPointIntegrate( float DeltaTime)
- {
- float halfDeltaT;
- halfDeltaT = DeltaTime / 2.0f;
- // 计算半步长
- IntegrateSysOverTime(g_CurrentSys,g_CurrentSys,&g_GameSys[2][0],halfDeltaT);
- // 使用新的位置和速度计算力
- ComputeForces(&g_GameSys[2][0]);
- // 计算全步长
- IntegrateSysOverTime(g_CurrentSys,&g_GameSys[2][0],g_TargetSys,DeltaTime);
- }
- int CBilliardView::CheckForCollisions( t_Ball *system )
- {
- int collisionState = NOT_COLLIDING;
- float const depthEpsilon = 0.001f;
- float const ballDepthEpsilon = 0.0001f;
- int loop,loop2,planeIndex;
- t_Ball *curBall,*ball2;
- t_CollisionPlane *plane;
- float axbyczd,dist,relativeVelocity;
- tVector distVect;
- g_ContactCnt = 0; // 目前的碰撞次数为0
- curBall = system;
- for (loop = 0;
- (loop < BALL_COUNT) && (collisionState != PENETRATING);
- loop++,curBall++)
- {
- // 判断球与边界面之间的碰撞
- for(planeIndex = 0;
- (planeIndex < g_CollisionPlaneCnt) && (collisionState != PENETRATING);
- planeIndex++)
- {
- plane = &g_CollisionPlane[planeIndex];
- axbyczd = m_MathDefs.DotProduct(&curBall->pos,&plane->normal) + plane->d;
- if(axbyczd < -depthEpsilon)
- {
- // 任何球穿过边界面,退出循环
- collisionState = PENETRATING;
- }
- else
- if(axbyczd < depthEpsilon)
- {
- relativeVelocity = m_MathDefs.DotProduct(&plane->normal,&curBall->v);
- if(relativeVelocity < 0.0f)
- {
- collisionState = COLLIDING_WITH_WALL;
- g_Contact[g_ContactCnt].type = COLLIDING_WITH_WALL;
- g_Contact[g_ContactCnt].ball = loop;
- g_Contact[g_ContactCnt].Kr = g_Kr_Bumper; // Ball to bumper Kr
- memcpy(&g_Contact[g_ContactCnt].normal,&plane->normal,sizeof(tVector));
- g_ContactCnt++;
- }
- }
- }
- // 现在判断球与球之间的碰撞
- ball2 = system;
- for (loop2 = 0; (loop2 < BALL_COUNT) && (collisionState != PENETRATING);
- loop2++,ball2++)
- {
- if (loop2 == loop) continue; // 不与自身比较
- if (curBall->flags) continue; // 如果当前球是碰撞球
- m_MathDefs.VectorDifference(&curBall->pos, &ball2->pos, &distVect);
- // 获得两球心之间的距离
- dist = m_MathDefs.VectorSquaredLength(&distVect);
- dist = dist - (BALL_DIAMETER * BALL_DIAMETER);
- // 判断两球之间是否穿过
- if(dist < -ballDepthEpsilon)
- {
- // 如果穿过,则退出
- collisionState = PENETRATING;
- }
- else
- if(dist < ballDepthEpsilon)
- {
- m_MathDefs.NormalizeVector(&distVect);
- // 获得相对速度
- relativeVelocity = m_MathDefs.DotProduct(&distVect,&curBall->v);
- // 如果相对速度小于0
- if(relativeVelocity < 0.0f)
- {
- collisionState = COLLIDING_WITH_BALL;
- g_Contact[g_ContactCnt].type = COLLIDING_WITH_BALL;
- g_Contact[g_ContactCnt].ball = loop;
- g_Contact[g_ContactCnt].ball2 = loop2;
- g_Contact[g_ContactCnt].Kr = g_Kr_Ball;
- memcpy(&g_Contact[g_ContactCnt].normal,&distVect,sizeof(tVector));
- ball2->flags = 1;
- g_ContactCnt++;
- }
- }
- }
- }
- return collisionState;
- }
- void CBilliardView::ResolveCollisions( t_Ball *system )
- {
- t_Contact *contact;
- t_Ball *ball,*ball2;
- float VdotN;
- tVector Vn,Vt,Vn1;
- int loop;
- contact = g_Contact;
- for (loop = 0; loop < g_ContactCnt; loop++,contact++)
- {
- ball = &system[contact->ball];
- // 计算 Vn
- VdotN = m_MathDefs.DotProduct(&contact->normal,&ball->v);
- m_MathDefs.ScaleVector(&contact->normal, VdotN, &Vn);
- // 计算 Vt
- m_MathDefs.VectorDifference(&ball->v, &Vn, &Vt);
- // 判断碰撞类型
- if (contact->type == COLLIDING_WITH_WALL) // 如果球与边界碰撞
- {
- // Vn乘以恢复系数
- m_MathDefs.ScaleVector(&Vn, contact->Kr, &Vn);
- // 设置新的速度
- m_MathDefs.VectorDifference(&Vt, &Vn, &ball->v);
- }
- else // 球与球之间碰撞
- {
- // Vn乘以恢复系数
- m_MathDefs.ScaleVector(&Vn, contact->Kr, &Vn1);
- // 设置新的速度
- m_MathDefs.VectorDifference(&Vt, &Vn1, &ball->v);
- ball2 = &system[contact->ball2];
- // 球2的Vn乘以恢复系数
- m_MathDefs.ScaleVector(&Vn, 1.0f - contact->Kr, &Vn1);
- // 设置球2的速度
- m_MathDefs.VectorSum(&Vn1,&ball2->v,&ball2->v);
- ball->flags = 0;
- ball2->flags = 0;
- }
- }
- }
- void CBilliardView::Simulate(float DeltaTime, BOOL running)
- {
- float CurrentTime = 0.0f;
- float TargetTime = DeltaTime;
- t_Ball *tempSys;
- int collisionState;
- while(CurrentTime < DeltaTime)
- {
- if (running)
- {
- // 定义各球的作用力
- ComputeForces(g_CurrentSys);
- // 如果出现碰撞穿透的现象,强制使用欧拉方法,否则提供选择
- if (g_CollisionRootFinding)
- {
- EulerIntegrate(TargetTime-CurrentTime);
- }
- else
- {
- switch (g_IntegratorType)
- {
- case EULER_INTEGRATOR:
- EulerIntegrate(TargetTime-CurrentTime);
- break;
- case MIDPOINT_INTEGRATOR:
- MidPointIntegrate(TargetTime-CurrentTime);
- break;
- }
- }
- }
- collisionState = CheckForCollisions(g_TargetSys);
- if(collisionState == PENETRATING)
- {
- // 将使用欧拉方法
- g_CollisionRootFinding = TRUE;
- // 将时间步长缩短
- TargetTime = (CurrentTime + TargetTime) / 2.0f;
- assert(fabs(TargetTime - CurrentTime) > EPSILON);
- }
- else
- {
- if(collisionState == COLLIDING_WITH_WALL || collisionState == COLLIDING_WITH_BALL)
- {
- int Counter = 0;
- do
- {
- ResolveCollisions(g_TargetSys);
- Counter++;
- } while((CheckForCollisions(g_TargetSys) >= COLLIDING_WITH_WALL) && (Counter < 500));
- assert(Counter < 500);
- g_CollisionRootFinding = FALSE;
- }
- // 进入下一步
- CurrentTime = TargetTime;
- TargetTime = DeltaTime;
- MAKEVECTOR(g_CueForce,0.0f,0.0f,0.0f); // 清除球杆的力
- // SWAP MY TWO SYSTEM BUFFERS SO I CAN DO IT AGAIN
- tempSys = g_CurrentSys;
- g_CurrentSys = g_TargetSys;
- g_TargetSys = tempSys;
- }
- }
- }
- float CBilliardView::GetTime( void )
- {
- static long StartMilliseconds;
- long CurrentMilliseconds;
- if(!StartMilliseconds)
- {
- StartMilliseconds = timeGetTime();
- }
- CurrentMilliseconds = timeGetTime();
- return (float)(CurrentMilliseconds - StartMilliseconds) / 1000.0f;
- }