484 lines
13 KiB
C++
484 lines
13 KiB
C++
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: polytest.c
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
#include "rend.h"
|
|
#include "globals.h"
|
|
#include "util.h"
|
|
#include "d3dsphr.h"
|
|
#include "polytest.h"
|
|
|
|
#define MAX_OBJECTS 20
|
|
#define CAMERA_POS_POLYGON 7.0f
|
|
#define CAMERA_POS_INTERSECTION 2.0f
|
|
|
|
/*
|
|
* Global to keep track of execute buffer
|
|
*/
|
|
static RendExecuteBuffer *lpExBuf;
|
|
|
|
/*
|
|
* Global for light
|
|
*/
|
|
static RendLight *prlight;
|
|
|
|
/*
|
|
* Global projection and view matrices
|
|
*/
|
|
static RendMatrix *pProj;
|
|
static RendMatrix *pView;
|
|
static D3DMATRIX proj = {
|
|
D3DVAL(2.0), D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0),
|
|
D3DVAL(0.0), D3DVAL(2.0), D3DVAL(0.0), D3DVAL(0.0),
|
|
D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1.0), D3DVAL(1.0),
|
|
D3DVAL(0.0), D3DVAL(0.0), D3DVAL(-1.0), D3DVAL(0.0)
|
|
};
|
|
static D3DMATRIX view = {
|
|
D3DVAL(1.0), D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0),
|
|
D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), D3DVAL(0.0),
|
|
D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0),
|
|
D3DVAL(0.0), D3DVAL(0.0), D3DVAL(7.0), D3DVAL(1.0)
|
|
};
|
|
|
|
/*
|
|
* A structure which holds the object's data
|
|
*/
|
|
static struct {
|
|
LPD3DVERTEX lpV; /* object's vertices */
|
|
LPD3DTRIANGLE lpTri; /* object's triangles */
|
|
int num_vertices, num_faces;
|
|
} objData;
|
|
|
|
typedef struct _orderElt {
|
|
float z;
|
|
RendExecuteBuffer *exeBuff;
|
|
} orderElt;
|
|
static orderElt order[MAX_OBJECTS];
|
|
|
|
static int NumSpheres;
|
|
typedef struct tagSphereData {
|
|
float vx, vy, vz;
|
|
float rx, ry, rz;
|
|
int age;
|
|
RendMatrix *pMr;
|
|
RendMatrix *pMdr;
|
|
RendMatrix *pMp;
|
|
RendMatrix *pMdp;
|
|
RendMatrix *pM;
|
|
RendTexture *pTex;
|
|
RendMaterial *lpmat;
|
|
RendExecuteBuffer *lpSetWorldExeBuf;
|
|
} SphereData;
|
|
static SphereData* sphere;
|
|
|
|
static float D, R, DMINUSR, DV, DR, DEPTH;
|
|
static UINT ORDER;
|
|
|
|
void
|
|
tick_sphere(int n)
|
|
{
|
|
float x, y, z;
|
|
D3DMATRIX Mp, Mdr, Mdp;
|
|
sphere[n].pMp->Get(&Mp);
|
|
x = (float)Mp._41;
|
|
y = (float)Mp._42;
|
|
z = (float)Mp._43;
|
|
if (x > DMINUSR || x < -DMINUSR) {
|
|
sphere[n].vx = -sphere[n].vx;
|
|
sphere[n].rz = -sphere[n].rz;
|
|
sphere[n].ry = -sphere[n].ry;
|
|
++sphere[n].age;
|
|
}
|
|
if (y > DMINUSR || y < -DMINUSR) {
|
|
sphere[n].vy = -sphere[n].vy;
|
|
sphere[n].rz = -sphere[n].rz;
|
|
sphere[n].rx = -sphere[n].rx;
|
|
++sphere[n].age;
|
|
}
|
|
if (z > DEPTH || z < -DEPTH) {
|
|
sphere[n].vz = -sphere[n].vz;
|
|
sphere[n].rx = -sphere[n].rx;
|
|
sphere[n].ry = -sphere[n].ry;
|
|
++sphere[n].age;
|
|
}
|
|
if (sphere[n].age) {
|
|
MakeRotMatrix(&Mdr, sphere[n].rx, sphere[n].ry, sphere[n].rz);
|
|
sphere[n].pMdr->Set(&Mdr);
|
|
MakePosMatrix(&Mdp, sphere[n].vx, sphere[n].vy, sphere[n].vz);
|
|
sphere[n].pMdp->Set(&Mdp);
|
|
sphere[n].age = 0;
|
|
}
|
|
}
|
|
|
|
static int __cdecl compareZ(const void* p1, const void* p2)
|
|
{
|
|
orderElt* h1 = (orderElt*) p1;
|
|
orderElt* h2 = (orderElt*) p2;
|
|
if (ORDER == FRONT_TO_BACK) {
|
|
if (h1->z > h2->z) return -1;
|
|
if (h1->z < h2->z) return 1;
|
|
} else {
|
|
if (h1->z < h2->z) return -1;
|
|
if (h1->z > h2->z) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
sortObjects(void)
|
|
{
|
|
int i;
|
|
D3DMATRIX M;
|
|
|
|
for (i = 0; i < NumSpheres; i++) {
|
|
sphere[i].pMp->Get(&M);
|
|
order[i].z = (float)M._43;
|
|
order[i].exeBuff = sphere[i].lpSetWorldExeBuf;
|
|
}
|
|
qsort(order, NumSpheres, sizeof(orderElt), compareZ);
|
|
}
|
|
|
|
/*
|
|
* Each frame, renders the scene and calls mod_buffer to modify the object
|
|
* for the next frame.
|
|
*/
|
|
BOOL
|
|
RenderScenePoly(RendWindow *prwin, LPD3DRECT lpExtent)
|
|
{
|
|
D3DRECT extent;
|
|
int j;
|
|
|
|
/*
|
|
* Execute the instruction buffer
|
|
*/
|
|
if (!prwin->BeginScene())
|
|
return FALSE;
|
|
|
|
if (ORDER != NO_SORT)
|
|
sortObjects();
|
|
|
|
for (j = 0; j < NumSpheres; j++) {
|
|
tick_sphere(j);
|
|
|
|
if (ORDER == NO_SORT) {
|
|
/* we can also be sure this is the poly throughput test */
|
|
if (!prwin->Execute(sphere[j].lpSetWorldExeBuf))
|
|
return FALSE;
|
|
if (!prwin->Execute(lpExBuf))
|
|
return FALSE;
|
|
} else {
|
|
/* must be intersection test */
|
|
if (!prwin->Execute(order[j].exeBuff))
|
|
return FALSE;
|
|
if (!prwin->ExecuteClipped(lpExBuf))
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (!prwin->EndScene(&extent))
|
|
return FALSE;
|
|
|
|
*lpExtent = extent;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Release the memory allocated for the scene and all D3D objects created.
|
|
*/
|
|
void
|
|
ReleaseViewPoly(void)
|
|
{
|
|
int i;
|
|
|
|
RELEASE(lpExBuf);
|
|
RELEASE(prlight);
|
|
|
|
for (i = 0; i < NumSpheres; i++) {
|
|
RELEASE(sphere[i].lpmat);
|
|
}
|
|
|
|
if (objData.lpV)
|
|
free(objData.lpV);
|
|
if (objData.lpTri)
|
|
free(objData.lpTri);
|
|
free(sphere);
|
|
}
|
|
|
|
unsigned long
|
|
init_spheres(RendWindow *prwin, int n)
|
|
{
|
|
D3DMATRIX Mp, Mdp, Mdr;
|
|
int i;
|
|
|
|
InitRandom();
|
|
sphere = (SphereData*)malloc(n*sizeof(SphereData));
|
|
memset(sphere, 0, n*sizeof(SphereData));
|
|
for (i = 0; i < n; i++) {
|
|
MakePosMatrix(&Mp, (float)DMINUSR - Random(2 * DMINUSR),
|
|
(float)DMINUSR - Random(2 * DMINUSR),
|
|
(float)-DEPTH + Random(2 * DEPTH));
|
|
MAKE_REND_MATRIX(prwin, sphere[i].pMp, Mp);
|
|
sphere[i].vx = (float)DV - Random(2 * DV);
|
|
sphere[i].vy = (float)DV - Random(2 * DV);
|
|
sphere[i].vz = (float)DV - Random(2 * DV);
|
|
MakePosMatrix(&Mdp, sphere[i].vx, sphere[i].vy, sphere[i].vz);
|
|
MAKE_REND_MATRIX(prwin, sphere[i].pMdp, Mdp);
|
|
sphere[i].rx = (float)DR - Random(2 * DR);
|
|
sphere[i].ry = (float)DR - Random(2 * DR);
|
|
sphere[i].rz = (float)DR - Random(2 * DR);
|
|
MakeRotMatrix(&Mdr, sphere[i].rx, sphere[i].ry, sphere[i].rz);
|
|
MAKE_REND_MATRIX(prwin, sphere[i].pMdr, Mdr);
|
|
MAKE_REND_MATRIX(prwin, sphere[i].pMr, dmIdentity);
|
|
MAKE_REND_MATRIX(prwin, sphere[i].pM, dmIdentity);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Builds the scene and initializes the execute buffer for rendering. Returns 0 on failure.
|
|
*/
|
|
|
|
#define ALPHA_COLOR_COUNT 3
|
|
static D3DCOLORVALUE dcvAlphaColors[ALPHA_COLOR_COUNT] =
|
|
{
|
|
1.0f, 0.0f, 0.0f, 0.25f,
|
|
0.0f, 1.0f, 0.0f, 0.50f,
|
|
0.0f, 0.0f, 1.0f, 0.75f
|
|
};
|
|
|
|
unsigned long
|
|
InitViewPoly(RendWindow *prwin,
|
|
int NumTextures, RendTexture **pprtex,
|
|
UINT num, UINT rings, UINT segs, UINT order,
|
|
float radius, float d, float depth,
|
|
float dv, float dr, BOOL bAlpha)
|
|
{
|
|
/* Pointers into the exectue buffer. */
|
|
LPVOID lpBufStart, lpInsStart, lpPointer;
|
|
RendExecuteBuffer *lpExCmdBuf;
|
|
size_t size;
|
|
int i;
|
|
|
|
D3DCOLORVALUE dcol;
|
|
D3DVECTOR dvec;
|
|
|
|
/* This sucks, but I'm tired */
|
|
D = d;
|
|
R = radius;
|
|
DMINUSR = d - radius;
|
|
DV = dv;
|
|
DR = dr;
|
|
DEPTH = depth;
|
|
ORDER = order;
|
|
|
|
NumSpheres = (int)num;
|
|
|
|
/*
|
|
* Generate the sphere.
|
|
*/
|
|
if (!(GenerateSphere(R, rings, segs, (float)1.0, (float)1.0,
|
|
(float)1.0, &objData.lpV, &objData.lpTri,
|
|
&objData.num_vertices, &objData.num_faces)))
|
|
return 0L;
|
|
|
|
/*
|
|
* Set the view and projection matrices, make the world matricies
|
|
*/
|
|
if (order == NO_SORT) {
|
|
view._43 = CAMERA_POS_POLYGON;
|
|
} else {
|
|
view._43 = CAMERA_POS_INTERSECTION;
|
|
}
|
|
|
|
MAKE_REND_MATRIX(prwin, pView, view);
|
|
MAKE_REND_MATRIX(prwin, pProj, proj);
|
|
|
|
/*
|
|
* Create buffers for world matrix set commands
|
|
*/
|
|
init_spheres(prwin, NumSpheres);
|
|
for (i = 0; i < NumSpheres; i++) {
|
|
|
|
/*
|
|
* Create a material, set its description and obtain a handle to it.
|
|
*/
|
|
sphere[i].lpmat = prwin->NewMaterial(32);
|
|
if (sphere[i].lpmat == NULL)
|
|
return 0L;
|
|
if (bAlpha)
|
|
{
|
|
dcol = dcvAlphaColors[i % ALPHA_COLOR_COUNT];
|
|
}
|
|
else
|
|
{
|
|
dcol.r = D3DVAL(1.0);
|
|
dcol.g = D3DVAL(1.0);
|
|
dcol.b = D3DVAL(1.0);
|
|
dcol.a = D3DVAL(1.0);
|
|
}
|
|
sphere[i].lpmat->SetDiffuse(&dcol);
|
|
sphere[i].lpmat->SetSpecular(&dcol, 40.0f);
|
|
sphere[i].pTex = pprtex[i % NumTextures];
|
|
sphere[i].lpmat->SetTexture(sphere[i].pTex);
|
|
|
|
size = 0;
|
|
size += sizeof(D3DINSTRUCTION) * 5;
|
|
size += sizeof(D3DMATRIXMULTIPLY) * 3;
|
|
size += sizeof(D3DSTATE) * 4;
|
|
sphere[i].lpSetWorldExeBuf =
|
|
prwin->NewExecuteBuffer(size, stat.uiExeBufFlags);
|
|
if (sphere[i].lpSetWorldExeBuf == NULL)
|
|
return 0L;
|
|
lpBufStart = sphere[i].lpSetWorldExeBuf->Lock();
|
|
if (lpBufStart == NULL)
|
|
return 0L;
|
|
memset(lpBufStart, 0, size);
|
|
lpPointer = lpBufStart;
|
|
lpInsStart = lpPointer;
|
|
OP_MATRIX_MULTIPLY(3, lpPointer);
|
|
MATRIX_MULTIPLY_REND_DATA(sphere[i].pMdr, sphere[i].pMr,
|
|
sphere[i].pMr, lpPointer);
|
|
MATRIX_MULTIPLY_REND_DATA(sphere[i].pMdp, sphere[i].pMp,
|
|
sphere[i].pMp, lpPointer);
|
|
MATRIX_MULTIPLY_REND_DATA(sphere[i].pMr, sphere[i].pMp,
|
|
sphere[i].pM, lpPointer);
|
|
OP_STATE_TRANSFORM(1, lpPointer);
|
|
STATE_DATA(D3DTRANSFORMSTATE_WORLD, sphere[i].pM->Handle(),
|
|
lpPointer);
|
|
OP_STATE_LIGHT(1, lpPointer);
|
|
STATE_DATA(D3DLIGHTSTATE_MATERIAL, sphere[i].lpmat->Handle(),
|
|
lpPointer);
|
|
OP_STATE_RENDER(2, lpPointer);
|
|
STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE,
|
|
(sphere[i].pTex != NULL ? sphere[i].pTex->Handle() : 0),
|
|
lpPointer);
|
|
STATE_DATA(D3DRENDERSTATE_WRAPU, TRUE, lpPointer);
|
|
OP_EXIT(lpPointer);
|
|
/*
|
|
* Setup the execute data describing the buffer
|
|
*/
|
|
sphere[i].lpSetWorldExeBuf->Unlock();
|
|
if (!sphere[i].lpSetWorldExeBuf->Process())
|
|
{
|
|
return 0L;
|
|
}
|
|
}
|
|
/*
|
|
* Create a buffer for matrix set commands etc.
|
|
*/
|
|
size = 0;
|
|
size += sizeof(D3DINSTRUCTION) * 6;
|
|
size += sizeof(D3DSTATE) * 6;
|
|
lpExCmdBuf = prwin->NewExecuteBuffer(size, stat.uiExeBufFlags);
|
|
if (lpExCmdBuf == NULL)
|
|
return 0L;
|
|
lpBufStart = lpExCmdBuf->Lock();
|
|
if (lpBufStart == NULL)
|
|
return 0L;
|
|
memset(lpBufStart, 0, size);
|
|
lpPointer = lpBufStart;
|
|
|
|
lpInsStart = lpPointer;
|
|
OP_STATE_TRANSFORM(2, lpPointer);
|
|
STATE_DATA(D3DTRANSFORMSTATE_VIEW, pView->Handle(), lpPointer);
|
|
STATE_DATA(D3DTRANSFORMSTATE_PROJECTION, pProj->Handle(), lpPointer);
|
|
OP_STATE_LIGHT(1, lpPointer);
|
|
STATE_DATA(D3DLIGHTSTATE_AMBIENT, RGBA_MAKE(10, 10, 10, 10),
|
|
lpPointer);
|
|
OP_STATE_RENDER(3, lpPointer);
|
|
STATE_DATA(D3DRENDERSTATE_BLENDENABLE, bAlpha, lpPointer);
|
|
STATE_DATA(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA, lpPointer);
|
|
STATE_DATA(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA, lpPointer);
|
|
OP_EXIT(lpPointer);
|
|
/*
|
|
* Setup the execute data describing the buffer
|
|
*/
|
|
lpExCmdBuf->Unlock();
|
|
if (!lpExCmdBuf->Process())
|
|
{
|
|
return 0L;
|
|
}
|
|
prwin->BeginScene();
|
|
prwin->Execute(lpExCmdBuf);
|
|
prwin->EndScene(NULL);
|
|
/*
|
|
* We are done with the command buffer.
|
|
*/
|
|
lpExCmdBuf->Release();
|
|
|
|
/*
|
|
* Create the object execute buffer
|
|
*/
|
|
size = sizeof(D3DVERTEX) * objData.num_vertices;
|
|
size += sizeof(D3DPROCESSVERTICES) * 1;
|
|
size += sizeof(D3DINSTRUCTION) * 4;
|
|
size += sizeof(D3DTRIANGLE) * objData.num_faces;
|
|
lpExBuf = prwin->NewExecuteBuffer(size, stat.uiExeBufFlags);
|
|
if (lpExBuf == NULL)
|
|
return 0L;
|
|
|
|
/*
|
|
* lock it so it can be filled
|
|
*/
|
|
lpBufStart = lpExBuf->Lock();
|
|
if (lpBufStart == NULL)
|
|
return 0L;
|
|
memset(lpBufStart, 0, size);
|
|
lpPointer = lpBufStart;
|
|
|
|
VERTEX_DATA(objData.lpV, objData.num_vertices, lpPointer);
|
|
/*
|
|
* Save the location of the first instruction and add instructions to
|
|
* execute buffer.
|
|
*/
|
|
lpInsStart = lpPointer;
|
|
OP_PROCESS_VERTICES(1, lpPointer);
|
|
PROCESSVERTICES_DATA(D3DPROCESSVERTICES_TRANSFORMLIGHT, 0,
|
|
objData.num_vertices, lpPointer);
|
|
/*
|
|
* Make sure that the triangle data (not OP) will be QWORD aligned
|
|
*/
|
|
if (QWORD_ALIGNED(lpPointer)) {
|
|
OP_NOP(lpPointer);
|
|
}
|
|
OP_TRIANGLE_LIST(objData.num_faces, lpPointer);
|
|
TRIANGLE_LIST_DATA(objData.lpTri, objData.num_faces, lpPointer);
|
|
OP_EXIT(lpPointer);
|
|
/*
|
|
* Setup the execute data describing the buffer
|
|
*/
|
|
lpExBuf->Unlock();
|
|
lpExBuf->SetData(objData.num_vertices,
|
|
(ULONG)((char*)lpInsStart - (char*)lpBufStart),
|
|
(ULONG)((char*)lpPointer - (char*)lpInsStart));
|
|
if (!lpExBuf->Process())
|
|
{
|
|
return 0L;
|
|
}
|
|
|
|
/*
|
|
* Create the light
|
|
*/
|
|
prlight = prwin->NewLight(REND_LIGHT_DIRECTIONAL);
|
|
if (prlight == NULL)
|
|
return 0L;
|
|
dcol.r = 0.9f;
|
|
dcol.g = 0.9f;
|
|
dcol.b = 0.9f;
|
|
dcol.a = 1.0f;
|
|
prlight->SetColor(&dcol);
|
|
dvec.x = 0.0f;
|
|
dvec.y = 0.0f;
|
|
dvec.z = 1.0f;
|
|
prlight->SetVector(&dvec);
|
|
|
|
return NumSpheres * objData.num_faces;
|
|
}
|