Initial import of Red Planet v4.10 Win32 source
Imports the current Win32 source for the pod-racing game 'Red Planet', built on the MUNGA engine and its L4 (Win32/DirectX) platform layer: - MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend - RP / RP_L4: Red Planet game logic and Win32 application - DivLoader, Setup1: asset loader and installer project - lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies Removed stale Subversion metadata and added .gitignore/.gitattributes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,464 @@
|
||||
#include "mungal4.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "l4d3d.h"
|
||||
#include "L4VIDEO.h"
|
||||
#include <algorithm>
|
||||
|
||||
int gNumBatches = 0;
|
||||
|
||||
bool d3d_OBJECT::mLastTextureScrollState = false;
|
||||
L4TEXOP::WrapType d3d_OBJECT::mLastWrapU = L4TEXOP::WrapType::REPEAT;
|
||||
L4TEXOP::WrapType d3d_OBJECT::mLastWrapV = L4TEXOP::WrapType::REPEAT;
|
||||
bool d3d_OBJECT::mLastTexturingState = true;
|
||||
long d3d_OBJECT::mNextID = 1;
|
||||
stdext::hash_map<std::string, L4TEXOP> d3d_OBJECT::mTextureCache;
|
||||
|
||||
void chgext(char *filePath, const char *newExtension)
|
||||
{
|
||||
int len = strlen(filePath);
|
||||
for (int i=len-1; i>=0; i--)
|
||||
{
|
||||
if (filePath[i] == '.')
|
||||
{
|
||||
strcpy(&filePath[i + 1], newExtension);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void d3d_OBJECT::ResetState(LPDIRECT3DDEVICE9 device)
|
||||
{
|
||||
d3d_OBJECT::mLastTextureScrollState = false;
|
||||
device->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
|
||||
|
||||
d3d_OBJECT::mLastWrapU = L4TEXOP::WrapType::REPEAT;
|
||||
device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
|
||||
|
||||
d3d_OBJECT::mLastWrapV = L4TEXOP::WrapType::REPEAT;
|
||||
device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
|
||||
|
||||
d3d_OBJECT::mLastTexturingState = true;
|
||||
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
}
|
||||
|
||||
d3d_OBJECT *d3d_OBJECT::LoadObject(LPDIRECT3DDEVICE9 device, char *fileName)
|
||||
{
|
||||
char fullPath[512];
|
||||
sprintf(fullPath, "VIDEO\\%s", fileName);
|
||||
chgext(fullPath, "x");
|
||||
|
||||
//Get a ref to the renderer
|
||||
DPLRenderer *renderer = l4_application->GetVideoRenderer();
|
||||
|
||||
LPD3DXMESH mesh;
|
||||
LPD3DXBUFFER materialBuffer, adjacencyBuffer;
|
||||
DWORD materialCount;
|
||||
|
||||
HRESULT hr = D3DXLoadMeshFromXA(fullPath, D3DXMESH_MANAGED, device, &adjacencyBuffer, &materialBuffer, NULL, &materialCount, &mesh);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
chgext(fullPath, "sph");
|
||||
return d3d_OBJECT::LoadSpheres(device, fullPath);
|
||||
}
|
||||
|
||||
chgext(fullPath, "det");
|
||||
FILE *detFile = fopen(fullPath, "rb");
|
||||
int numDetailOps = 0;
|
||||
int *detailOps = NULL;
|
||||
|
||||
bool isSky = false;
|
||||
|
||||
if (detFile != NULL)
|
||||
{
|
||||
fread(&numDetailOps, sizeof(int), 1, detFile);
|
||||
|
||||
detailOps = new int[numDetailOps];
|
||||
fread(detailOps, sizeof(int), numDetailOps, detFile);
|
||||
fclose(detFile);
|
||||
}
|
||||
|
||||
chgext(fullPath, "sky");
|
||||
FILE *skyFile = fopen(fullPath, "rb");
|
||||
|
||||
if (skyFile != NULL)
|
||||
{
|
||||
isSky = true;
|
||||
fclose(skyFile);
|
||||
}
|
||||
|
||||
d3d_OBJECT *object = new d3d_OBJECT(device, mesh, (DWORD*)adjacencyBuffer->GetBufferPointer(), materialCount);
|
||||
|
||||
D3DXMATERIAL *materials = (D3DXMATERIAL*)materialBuffer->GetBufferPointer();
|
||||
|
||||
int nextDetailOp = 0;
|
||||
|
||||
for (DWORD i = 0; i < materialCount; i++)
|
||||
{
|
||||
chgext(fullPath, "BGF");
|
||||
|
||||
string path(fullPath);
|
||||
|
||||
string actualPath = path.substr(path.find("\\") + 1);
|
||||
std::transform(actualPath.begin(), actualPath.end(), actualPath.begin(), toupper);
|
||||
const char *matName = opMaterialName(actualPath.c_str(), i);
|
||||
char *replaceMatName = NULL;
|
||||
char *replaceTexName = NULL;
|
||||
|
||||
if (matName != NULL)
|
||||
{
|
||||
char *tmpMatName = new char[strlen(matName) + 1];
|
||||
strcpy_s(tmpMatName, strlen(matName) + 1, matName);
|
||||
|
||||
replaceMatName = substituteMaterial(tmpMatName);
|
||||
}
|
||||
|
||||
object->mDrawOps[i].material = materials[i].MatD3D;
|
||||
|
||||
if (replaceMatName != NULL)
|
||||
{
|
||||
hash_map<string, ReplacementMaterialData>::const_iterator iter = gReplacementData->find(string(replaceMatName));
|
||||
|
||||
ReplacementMaterialData data = (*iter).second;
|
||||
|
||||
object->mDrawOps[i].material.Diffuse.r = data.r;
|
||||
object->mDrawOps[i].material.Diffuse.g = data.g;
|
||||
object->mDrawOps[i].material.Diffuse.b = data.b;
|
||||
|
||||
replaceTexName = new char[data.texName.size() + 1];
|
||||
strcpy_s(replaceTexName, data.texName.size() + 1, data.texName.c_str());
|
||||
|
||||
delete [] replaceMatName;
|
||||
}
|
||||
|
||||
//TODO: set ambient of material; doesn't come back from .X file
|
||||
object->mDrawOps[i].material.Ambient = object->mDrawOps[i].material.Diffuse;
|
||||
|
||||
object->mDrawOps[i].texture.texture = NULL;
|
||||
if (materials[i].pTextureFilename || replaceTexName)
|
||||
{
|
||||
char textureFilename[512];
|
||||
|
||||
if (replaceTexName)
|
||||
{
|
||||
sprintf(textureFilename, "VIDEO\\%s.png", replaceTexName);
|
||||
delete [] replaceTexName;
|
||||
} else
|
||||
{
|
||||
sprintf(textureFilename, "VIDEO\\%s", materials[i].pTextureFilename);
|
||||
}
|
||||
object->mDrawOps[i].texture = LoadTexture(device, textureFilename);
|
||||
}
|
||||
|
||||
if (nextDetailOp < numDetailOps && detailOps[nextDetailOp] == i)
|
||||
{
|
||||
object->mDrawOps[i].drawAsDecal = true;
|
||||
nextDetailOp++;
|
||||
}
|
||||
|
||||
if (abs(object->mDrawOps[i].material.Diffuse.a - 1.0f) > 0.0001f)
|
||||
{
|
||||
object->mDrawOps[i].alphaTest = true;
|
||||
}
|
||||
|
||||
object->mDrawOps[i].drawAsSky = isSky;
|
||||
|
||||
if (isSky)
|
||||
{
|
||||
object->mDrawOps[i].material.Ambient.r *= renderer->GetCloudRed();
|
||||
object->mDrawOps[i].material.Ambient.g *= renderer->GetCloudGreen();
|
||||
object->mDrawOps[i].material.Ambient.b *= renderer->GetCloudBlue();
|
||||
object->mDrawOps[i].material.Diffuse.r *= renderer->GetCloudRed();
|
||||
object->mDrawOps[i].material.Diffuse.g *= renderer->GetCloudGreen();
|
||||
object->mDrawOps[i].material.Diffuse.b *= renderer->GetCloudBlue();
|
||||
object->mDrawOps[i].material.Emissive.r = renderer->GetCloudEmitRed();
|
||||
object->mDrawOps[i].material.Emissive.g = renderer->GetCloudEmitGreen();
|
||||
object->mDrawOps[i].material.Emissive.b = renderer->GetCloudEmitBlue();
|
||||
}
|
||||
}
|
||||
|
||||
materialBuffer->Release();
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
d3d_OBJECT* d3d_OBJECT::LoadSpheres(LPDIRECT3DDEVICE9 device, char *fileName)
|
||||
{
|
||||
FILE *file;
|
||||
float emissionColor[3];
|
||||
int vertexCount;
|
||||
|
||||
if ((file = fopen(fileName, "rb")) == NULL)
|
||||
return NULL;
|
||||
|
||||
fread(emissionColor, sizeof(float), 3, file);
|
||||
fread(&vertexCount, sizeof(int), 1, file);
|
||||
|
||||
d3d_OBJECT *object = new d3d_OBJECT(device, vertexCount);
|
||||
void *buffer = NULL;
|
||||
|
||||
object->mVB->Lock(0, 0, &buffer, 0);
|
||||
|
||||
fread(buffer, sizeof(L4POINTVERTEX), vertexCount, file);
|
||||
|
||||
D3DXVECTOR3 center(0, 0, 0);
|
||||
D3DXComputeBoundingSphere((D3DXVECTOR3*)buffer, vertexCount, sizeof(L4POINTVERTEX), ¢er, &object->mRadius);
|
||||
|
||||
object->mVB->Unlock();
|
||||
|
||||
object->mDrawOps[0].material.Emissive.r = emissionColor[0];
|
||||
object->mDrawOps[0].material.Emissive.g = emissionColor[1];
|
||||
object->mDrawOps[0].material.Emissive.b = emissionColor[2];
|
||||
object->mDrawOps[0].material.Emissive.a = 1.0f;
|
||||
|
||||
fclose(file);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
L4TEXOP d3d_OBJECT::LoadTexture(LPDIRECT3DDEVICE9 device, const char *fileName)
|
||||
{
|
||||
L4TEXOP texOp;
|
||||
FILE *file;
|
||||
if (mTextureCache.find(fileName) == mTextureCache.end())
|
||||
{
|
||||
struct
|
||||
{ unsigned char minify;
|
||||
unsigned char magnify;
|
||||
unsigned char alpha;
|
||||
unsigned char wrap_u;
|
||||
unsigned char wrap_v;
|
||||
bool doScroll;
|
||||
float scrollUDelta;
|
||||
float scrollVDelta;
|
||||
} fileTexOp;
|
||||
|
||||
char metFileName[512];
|
||||
strcpy(metFileName, fileName);
|
||||
chgext(metFileName, "met");
|
||||
|
||||
memset(&texOp, 0, sizeof(L4TEXOP));
|
||||
if ((file = fopen(metFileName, "rb")) != NULL)
|
||||
{
|
||||
fread(&fileTexOp, sizeof(fileTexOp), 1, file);
|
||||
fclose(file);
|
||||
|
||||
texOp.wrap_u = (L4TEXOP::WrapType)fileTexOp.wrap_u;
|
||||
texOp.wrap_v = (L4TEXOP::WrapType)fileTexOp.wrap_v;
|
||||
texOp.doScroll = fileTexOp.doScroll;
|
||||
texOp.scrollUDelta = fileTexOp.scrollUDelta;
|
||||
texOp.scrollVDelta = fileTexOp.scrollVDelta;
|
||||
}
|
||||
|
||||
D3DXCreateTextureFromFileA(device, fileName, &texOp.texture);
|
||||
|
||||
mTextureCache.insert(std::pair<std::string,L4TEXOP>(std::string(fileName), texOp));
|
||||
}
|
||||
else
|
||||
texOp = mTextureCache[std::string(fileName)];
|
||||
|
||||
texOp.texture->AddRef();
|
||||
return texOp;
|
||||
}
|
||||
|
||||
d3d_OBJECT::d3d_OBJECT(LPDIRECT3DDEVICE9 device, int vertCount)
|
||||
: mDevice(device),
|
||||
mVertCount(vertCount),
|
||||
mDrawOpCount(1),
|
||||
mImmune(false),
|
||||
mVB(NULL),
|
||||
mMesh(NULL),
|
||||
mDrawOps(NULL),
|
||||
mLocalToWorld(),
|
||||
mOrigin(),
|
||||
mRadius(0.0f),
|
||||
mID(mNextID++)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
hr = device->CreateVertexBuffer(vertCount * sizeof(L4POINTVERTEX), D3DUSAGE_WRITEONLY, L4POINTVERTEX_FVF, D3DPOOL_MANAGED, &mVB, NULL);
|
||||
|
||||
mDrawOps = new L4DRAWOP();
|
||||
memset(mDrawOps, 0, sizeof(L4DRAWOP));
|
||||
|
||||
memset(mNext, 0, sizeof(mNext));
|
||||
memset(mPrev, 0, sizeof(mPrev));
|
||||
|
||||
D3DXMatrixIdentity(&mLocalToWorld);
|
||||
}
|
||||
|
||||
d3d_OBJECT::d3d_OBJECT(LPDIRECT3DDEVICE9 device, LPD3DXMESH mesh, DWORD *adjacencyBuffer, int drawOpCount)
|
||||
: mDevice(device),
|
||||
mVertCount(-1),
|
||||
mDrawOpCount(drawOpCount),
|
||||
mImmune(false),
|
||||
mVB(NULL),
|
||||
mMesh(mesh),
|
||||
mLocalToWorld(),
|
||||
mOrigin(),
|
||||
mRadius(0.0f),
|
||||
mID(mNextID++)
|
||||
{
|
||||
mDrawOps = new L4DRAWOP[drawOpCount];
|
||||
memset(mDrawOps, 0, sizeof(L4DRAWOP) * drawOpCount);
|
||||
|
||||
if (adjacencyBuffer != NULL)
|
||||
{
|
||||
//Null adjacency buffer means the mesh should have already been optimized
|
||||
mesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, adjacencyBuffer, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
DWORD vertCount = mesh->GetNumVertices();
|
||||
DWORD vertStride = mesh->GetNumBytesPerVertex();
|
||||
|
||||
D3DXVECTOR3 *data;
|
||||
D3DXVECTOR3 center(0, 0, 0);
|
||||
mesh->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&data);
|
||||
D3DXComputeBoundingSphere(data, vertCount, vertStride, ¢er, &mRadius);
|
||||
mesh->UnlockVertexBuffer();
|
||||
|
||||
memset(mNext, 0, sizeof(mNext));
|
||||
memset(mPrev, 0, sizeof(mPrev));
|
||||
|
||||
D3DXMatrixIdentity(&mLocalToWorld);
|
||||
}
|
||||
|
||||
d3d_OBJECT::~d3d_OBJECT()
|
||||
{
|
||||
if (mVB)
|
||||
{
|
||||
mVB->Release();
|
||||
mVB = NULL;
|
||||
}
|
||||
if (mDrawOps)
|
||||
{
|
||||
delete[] mDrawOps;
|
||||
mDrawOps = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void d3d_OBJECT::Draw(int pass, const D3DXMATRIX *viewTransform, Time targetRenderFrame)
|
||||
{
|
||||
// set our world transform
|
||||
mDevice->SetTransform(D3DTS_WORLD, &mLocalToWorld);
|
||||
|
||||
if (mMesh != NULL && pass != PASS_SPHERE)
|
||||
return DrawMesh(pass, viewTransform, targetRenderFrame);
|
||||
else if (mMesh == NULL && mVB != NULL && pass == PASS_SPHERE)
|
||||
return DrawSpheres(pass, viewTransform);
|
||||
}
|
||||
|
||||
void d3d_OBJECT::DrawMesh(int pass, const D3DXMATRIX *viewTransform, Time targetRenderFrame)
|
||||
{
|
||||
for (int iOp = 0; iOp < mDrawOpCount; iOp++)
|
||||
{
|
||||
L4DRAWOP *drawOp = &mDrawOps[iOp];
|
||||
|
||||
if (drawOp->alphaTest != (pass == PASS_ALPHABLEND))
|
||||
continue;
|
||||
|
||||
if (drawOp->drawAsDecal != (pass == PASS_DECAL))
|
||||
continue;
|
||||
|
||||
if (drawOp->drawAsSky != (pass == PASS_SKY))
|
||||
continue;
|
||||
|
||||
mDevice->SetMaterial(&drawOp->material);
|
||||
|
||||
#ifndef RP3_EMULATE
|
||||
SetTextureScrolling(&(drawOp->texture), targetRenderFrame);
|
||||
SetTexture(drawOp->texture.texture);
|
||||
#endif
|
||||
|
||||
gNumBatches++;
|
||||
mMesh->DrawSubset(iOp);
|
||||
}
|
||||
}
|
||||
|
||||
void d3d_OBJECT::DrawSpheres(int pass, const D3DXMATRIX *viewTransform)
|
||||
{
|
||||
mDevice->SetFVF(L4POINTVERTEX_FVF);
|
||||
mDevice->SetStreamSource(0, mVB, 0, sizeof(L4POINTVERTEX));
|
||||
mDevice->SetMaterial(&mDrawOps[0].material);
|
||||
SetTexture(NULL);
|
||||
mDevice->DrawPrimitive(D3DPT_POINTLIST, 0, mVertCount);
|
||||
}
|
||||
|
||||
void d3d_OBJECT::SetTextureScrolling(const L4TEXOP *texture, Time targetRenderFrame)
|
||||
{
|
||||
if (d3d_OBJECT::mLastTextureScrollState != texture->doScroll)
|
||||
{
|
||||
// the texture scrolling state has changed
|
||||
if (texture->doScroll)
|
||||
{
|
||||
mDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
|
||||
SetTextureAddressing(texture->wrap_u, texture->wrap_v);
|
||||
}
|
||||
else
|
||||
{
|
||||
mDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
|
||||
SetTextureAddressing(L4TEXOP::WrapType::REPEAT, L4TEXOP::WrapType::REPEAT);
|
||||
}
|
||||
d3d_OBJECT::mLastTextureScrollState = texture->doScroll;
|
||||
}
|
||||
|
||||
// if the texture is supposed to be scrolled then
|
||||
// we have to set the transforms regardless of state
|
||||
if (texture->doScroll)
|
||||
{
|
||||
Scalar time = (Scalar)targetRenderFrame;
|
||||
|
||||
D3DXMATRIX translate;
|
||||
D3DXMatrixIdentity(&translate);
|
||||
translate._31 = -texture->scrollUDelta * time;
|
||||
translate._32 = texture->scrollVDelta * time;
|
||||
mDevice->SetTransform(D3DTS_TEXTURE0, &translate);
|
||||
}
|
||||
}
|
||||
|
||||
void d3d_OBJECT::SetTextureAddressing(L4TEXOP::WrapType wrap_u, L4TEXOP::WrapType wrap_v)
|
||||
{
|
||||
if (wrap_u != d3d_OBJECT::mLastWrapU)
|
||||
{
|
||||
d3d_OBJECT::mLastWrapU = wrap_u;
|
||||
if (wrap_u == L4TEXOP::REPEAT)
|
||||
mDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
|
||||
else if (wrap_u == L4TEXOP::CLAMP)
|
||||
mDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
|
||||
else if (wrap_u == L4TEXOP::SELECT)
|
||||
mDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
|
||||
}
|
||||
if (wrap_v != d3d_OBJECT::mLastWrapV)
|
||||
{
|
||||
d3d_OBJECT::mLastWrapV = wrap_v;
|
||||
if (wrap_v == L4TEXOP::REPEAT)
|
||||
mDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
|
||||
else if (wrap_v == L4TEXOP::CLAMP)
|
||||
mDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
|
||||
else if (wrap_v == L4TEXOP::SELECT)
|
||||
mDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
|
||||
}
|
||||
}
|
||||
|
||||
void d3d_OBJECT::SetTexture(LPDIRECT3DTEXTURE9 texture)
|
||||
{
|
||||
bool texturingOn = (texture != NULL);
|
||||
if (texturingOn != d3d_OBJECT::mLastTexturingState)
|
||||
{
|
||||
d3d_OBJECT::mLastTexturingState = texturingOn;
|
||||
if (texturingOn)
|
||||
{
|
||||
mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
mDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
}
|
||||
else
|
||||
mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||||
}
|
||||
if (texture != NULL)
|
||||
{
|
||||
mDevice->SetTexture(0, texture);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user