📄 tunnel.cpp
字号:
joint[spoke] = D3DVERTEX(p + pt * TUBE_R, -pt,
1.0f - theta / (float) (2.0f * PI), tv);
}
}
/*
* Defines the triangles which form a segment between ring1 and ring2 and
* stores them at lpTri. lpTri must be pre-allocated.
*/
void
MakeSegment(int ring1, int ring2, LPD3DTRIANGLE lpTri)
{
int side, triangle = 0;
for (side = 0; side < SIDES; side++) {
/*
* Each side consists of two triangles.
*/
lpTri[triangle].v1 = ring1 * SIDES + side;
lpTri[triangle].v2 = ring2 * SIDES + side;
lpTri[triangle].v3 = ring2 * SIDES + ((side + 1) % SIDES);
/*
* for wireframe only need first two edges.
* Start a two triangle flat fan for each tunnel face.
*/
lpTri[triangle].wFlags = D3DTRIFLAG_STARTFLAT(1);
lpTri[triangle].wFlags |= D3DTRIFLAG_EDGEENABLE1 |
D3DTRIFLAG_EDGEENABLE2;
triangle++;
lpTri[triangle].v2 = ring2 * SIDES + ((side + 1) % SIDES);
lpTri[triangle].v3 = ring1 * SIDES + ((side + 1) % SIDES);
lpTri[triangle].v1 = ring1 * SIDES + side;
/*
* Dont need any edges for wireframe.
*/
lpTri[triangle].wFlags = D3DTRIFLAG_EVEN;
triangle++;
}
}
/*
* Creates a new segment of the tunnel at the current end position.
* Creates a new ring and segment.
*/
void
UpdateTubeInMemory(void)
{
static int texRing = 0; /* Static counter defining the position of
* this ring on the texture.
*/
int endRing; /* The ring at the end of the tube in memory. */
int RingOffset, SegmentOffset; /* Offsets into the vertex and triangle
* lists for the new data.
*/
/*
* Replace the back ring with a new ring at the front of the tube
* in memory.
*/
memmove(&tube.lpV[SIDES], &tube.lpV[0], sizeof(tube.lpV[0]) * (NUM_V - SIDES));
MakeRing(tube.endP, tube.endD, tube.endN, texRing/(float)TEX_RINGS,
&tube.lpV[0]);
/*
* Replace the back segment with a new segment at the front of the
* tube in memory. Update the current end position of the tube in
* memory.
*/
endRing = (tube.currentRing + SEGMENTS) % (SEGMENTS + 1);
MoveToPosition(tube.endPos, &tube.endP, &tube.endD, &tube.endN);
/*
* Update the execute buffer with the new vertices and triangles.
*/
RingOffset = sizeof(D3DVERTEX) * tube.currentRing * SIDES;
SegmentOffset = sizeof(D3DTRIANGLE) * tube.currentSegment * SIDES * 2;
memset(&debDesc, 0, sizeof(D3DEXECUTEBUFFERDESC));
debDesc.dwSize = sizeof(D3DEXECUTEBUFFERDESC);
if (lpD3DExBuf->Lock(&debDesc) != D3D_OK)
return;
memcpy((char *) debDesc.lpData,
&tube.lpV[0], sizeof(D3DVERTEX) * NUM_V);
lpD3DExBuf->Unlock();
/*
* Update the position of the back of the tube in memory and texture
* counter.
*/
tube.currentRing = (tube.currentRing + 1) % (SEGMENTS + 1);
tube.currentSegment = (tube.currentSegment + 1) % SEGMENTS;
texRing = (texRing + 1) % TEX_RINGS;
}
/*
* Move the camera through the tunnel. Create new segments of the tunnel
* when the camera gets close to the end of the section in memory.
*/
void
MoveCamera(LPDIRECT3DDEVICE lpDev, LPDIRECT3DVIEWPORT lpView)
{
/*
* Update the position on curve and camera vectors.
*/
tube.cameraPos += (float)SPEED;
if (tube.cameraPos > PATH_LENGTH)
tube.cameraPos -= PATH_LENGTH;
MoveToPosition(tube.cameraPos, &tube.cameraP, &tube.cameraD,
&tube.cameraN);
/*
* If the camera is close to the end, add a new segment.
*/
if (tube.endPos - tube.cameraPos < DEPTH) {
tube.endPos = tube.endPos + (float)SEGMENT_LENGTH;
if (tube.endPos > PATH_LENGTH)
tube.endPos -= PATH_LENGTH;
UpdateTubeInMemory();
}
}
// update the location of the spot in camera space
// need to be executed only if are NOT in the SCREEN_COORDINATES mode
// or we use the BLT_COMPOSITE method
void updateSWPolygon()
{
#ifndef SCREEN_COORDINATES
if( compositeMethod == TEXTUREMAP_COMPOSITE) {
moveSWPolygon();
memset(&debDesc, 0, sizeof(D3DEXECUTEBUFFERDESC));
debDesc.dwSize = sizeof(D3DEXECUTEBUFFERDESC);
if (lpD3DExBufSpot->Lock(&debDesc) != D3D_OK)
return;
memcpy((char *) debDesc.lpData, &src_v[0], sizeof(D3DTLVERTEX) * NUM_VERTICES_SPOT);
lpD3DExBufSpot->Unlock();
}
#endif
}
/*
* Modify the buffer between rendering frames
*/
static void
TickScene(LPDIRECT3DDEVICE lpDev, LPDIRECT3DVIEWPORT lpView)
{
MoveCamera(lpDev, lpView);
updateSWPolygon();
}
/*
* Each frame, renders the scene and calls TickScene to modify the object
* for the next frame.
*/
BOOL
RenderScene(LPDIRECT3DDEVICE lpDev, LPDIRECT3DVIEWPORT lpView,
LPD3DRECT lpExtent)
{
HRESULT ddrval;
BOOL loadResult;
/*
* Move the camera by updating the view matrix and move the light.
*/
PositionCamera(&tube.cameraP, &tube.cameraD, &tube.cameraN, &view);
ddrval = lpDev->SetMatrix(hView, &view);
if (ddrval != D3D_OK)
return FALSE;
tube.light.dvPosition = tube.cameraP;
ddrval = tube.lpD3DLight->SetLight(&tube.light);
if (ddrval != D3D_OK)
return FALSE;
if( compositeMethod == TEXTUREMAP_COMPOSITE)
{
// Here is one of the synchronization calls.
// The timeout is 1 second so at least it would move if deadlock were possible
WaitForSingleObject(eventHandle, 1000);
// OK, now reset the event and go onto the composite
ResetEvent(eventHandle);
// now we add the quads drawn by the SW thread to the statistics
sw_quads_drawn += sw_quads_per_frame ;
// Switch the active and the develope buffers and continue
lpDDTempSurfaceSystem = lpDDActiveSurfaceSystem;
lpDDActiveSurfaceSystem = lpDDDevelopSurfaceSystem;
lpDDDevelopSurfaceSystem = lpDDTempSurfaceSystem;
// Resume the SW Thread - that is, the main thread has consumed the
// output of the SW rendering.
// We Use double buffering so letting the SW to go ahead to the next frame early
SetEvent(compositeHandle);
// Load texture from the SW thread to be used in the HW scene in the next frame.
loadResult = LoadTextureFromSW();
if(! loadResult)
return FALSE;
/* * Execute the instruction buffer and update the view */
ddrval = lpDev->BeginScene();
if (ddrval != D3D_OK)
return FALSE;
ddrval = lpDev->Execute(lpD3DExBuf, lpView, D3DEXECUTE_CLIPPED);
if (ddrval != D3D_OK) return FALSE;
ddrval = lpDev->Execute(lpD3DExBufSpot, lpView, D3DEXECUTE_UNCLIPPED);
if (ddrval != D3D_OK) {
char * error_str = D3DAppErrorToString(ddrval);
Msg(error_str,0);
return FALSE;
}
ddrval = lpDev->EndScene();
if (ddrval != D3D_OK) return FALSE;
ddrval = lpD3DExBuf->GetExecuteData(&d3dExData);
if (ddrval != D3D_OK) return FALSE;
ddrval = lpD3DExBufSpot->GetExecuteData(&d3dExDataSpot);
if (ddrval != D3D_OK) return FALSE;
*lpExtent = d3dExData.dsStatus.drExtent;
}
else // compositeMethod == BLT_COMPOSITE)
{
/* * Execute the instruction buffer and update the view */
ddrval = lpDev->BeginScene();
if (ddrval != D3D_OK)
return FALSE;
ddrval = lpDev->Execute(lpD3DExBuf, lpView, D3DEXECUTE_CLIPPED);
if (ddrval != D3D_OK) return FALSE;
ddrval = lpDev->EndScene();
if (ddrval != D3D_OK) return FALSE;
ddrval = lpD3DExBuf->GetExecuteData(&d3dExData);
if (ddrval != D3D_OK) return FALSE;
*lpExtent = d3dExData.dsStatus.drExtent;
// Here is one of the synchronization calls.
// The timeout is 1 second so at least it would move if deadlock were possible
WaitForSingleObject(eventHandle, 1000);
// OK, now reset the event and go onto the composite
ResetEvent(eventHandle);
// now we add the quads drawn by the SW thread to the statistics
sw_quads_drawn += sw_quads_per_frame ;
}
/*
* Modify for the next time around
*/
TickScene(lpDev, lpView);
return TRUE;
}
void
OverrideDefaults(Defaults* defaults)
{
defaults->rs.bZBufferOn = FALSE;
defaults->rs.bPerspCorrect = TRUE;
defaults->bClearsOn = FALSE;
lstrcpy(defaults->Name, "Tunnel D3D Example");
}
BOOL
InitScene(void)
{
float position; /* Curve position counter. */
int i; /* counter */
/*
* Reserved memory for vertices, triangles and spline points.
*/
tube.lpV = (LPD3DVERTEX) malloc(sizeof(D3DVERTEX) * NUM_V);
tube.lpTri = (LPD3DTRIANGLE) malloc(sizeof(D3DTRIANGLE) * NUM_TRI);
tube.lpPoints = (LPD3DVECTOR) malloc(sizeof(D3DVECTOR)*SPLINE_POINTS);
/*
* Generate spline points
*/
for (i = 0; i < SPLINE_POINTS; i++) {
tube.lpPoints[i].x = (float)(cos(i * 4.0) * 20.0);
tube.lpPoints[i].y = (float)(sin(i * 4.0) * 20.0);
tube.lpPoints[i].z = i * 20.0f;
}
/*
* Create the initial tube section in memory.
*/
tube.endN.x = (float)0.0;
tube.endN.y = (float)1.0;
tube.endN.z = (float)0.0;
position = (float)0.0;
for (i = 0; i < SEGMENTS + 1; i++) {
MoveToPosition(position, &tube.endP, &tube.endD, &tube.endN);
position += (float)SEGMENT_LENGTH;
MakeRing(tube.endP, tube.endD, tube.endN,
(float)(i % TEX_RINGS) / TEX_RINGS,
&tube.lpV[(SEGMENTS - i) * SIDES]);
}
for (i = 0; i < SEGMENTS; i++)
MakeSegment(i + 1, i, &tube.lpTri[i * SIDES * 2]);
/*
* Move the camera to the begining and set some globals
*/
tube.cameraN.x = (float)0.0;
tube.cameraN.y = (float)1.0;
tube.cameraN.z = (float)0.0;
MoveToPosition((float)0.0, &tube.cameraP, &tube.cameraD, &tube.cameraN);
tube.currentRing = 0;
tube.currentSegment = 0;
tube.cameraPos = (float)0.0;
tube.endPos = position;
#if defined(SW_SPOT)
initSwSpot();
upVec.x = (float)0.0;
upVec.y = (float)1.0;
upVec.z = (float)0.0;
#ifndef SCREEN_COORDINATES
moveSWPolygon();
#endif
#endif
return TRUE;
}
void
ReleaseScene(void)
{
if (tube.lpPoints)
free(tube.lpPoints);
if (tube.lpTri)
free(tube.lpTri);
if (tube.lpV)
free(tube.lpV);
}
void
ReleaseView(LPDIRECT3DVIEWPORT lpView)
{
if (lpView)
lpView->DeleteLight(tube.lpD3DLight);
RELEASE(lpD3DExBuf);
RELEASE(tube.lpD3DLight);
RELEASE(lpmat);
RELEASE(lpbmat);
#if defined(SW_SPOT)
RELEASE(lpD3DExBufSpot);
#endif
}
/*
* Builds the scene and initializes the execute buffer for rendering.
* Returns 0 on failure.
*/
BOOL
InitView(LPDIRECTDRAW lpDD, LPDIRECT3D lpD3D, LPDIRECT3DDEVICE lpDev,
LPDIRECT3DVIEWPORT lpView, int NumTextures,
LPD3DTEXTUREHANDLE TextureHandle)
{
/* Variables for exectue buffer generation */
LPVOID lpBufStart, lpInsStart, lpPointer;
LPDIRECT3DEXECUTEBUFFER lpD3DExCmdBuf;
DWORD size;
/* Background material variables */
D3DMATERIAL bmat;
D3DMATERIALHANDLE hbmat;
D3DMATERIAL mat;
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -