The plates beside each spot came out blank. They ask for textures called player1..player8, which are not files - the renderer draws each pilot's callsign into a texture at run time - so the load failed and left them untextured. Nothing bound the two together. SortAndReloadNameBitmaps already builds those textures indexed by finishing place, which is exactly how the plates are numbered, so the plate beside each spot wants mNameTextures[place]. Binding them is the whole fix, but it takes two steps rather than one. The plates have to survive mesh consolidation first. Static geometry is merged with D3DXConcatenateMeshes and its draw ops deduped by material - and eight failed texture loads leave eight identical untextured ops, so all eight plates collapse into one that could only ever carry a single name. Each plate now gets a distinct 1x1 marker texture as it loads, which keeps it a subset of its own. The marker is never seen. Then the binding runs against the consolidated mesh, not the objects the plates were loaded from - by podium time those have been merged away and are no longer drawn, which is why re-pointing them changed nothing. Verified on a race: 8 plates found in the consolidated mesh, 1 bound, and the winner's plate reads their callsign under their vehicle. One bound of eight is right for a single-pod race - the rest of the places have nobody in them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
566 lines
15 KiB
C++
566 lines
15 KiB
C++
#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;
|
|
LPDIRECT3DTEXTURE9 d3d_OBJECT::mNamePlateMarkers[d3d_OBJECT::kNamePlateCount + 1] = { NULL };
|
|
|
|
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));
|
|
|
|
if (iter != gReplacementData->end())
|
|
{
|
|
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());
|
|
}
|
|
else
|
|
{
|
|
DEBUG_STREAM << "L4D3D.cpp no replacement material data for " << replaceMatName << "\n" << std::flush;
|
|
}
|
|
|
|
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);
|
|
}
|
|
//
|
|
// playerN is not a file - it is a pilot's callsign, drawn into
|
|
// a texture at run time, so loading it always fails. Give the
|
|
// plate its marker texture instead: it keeps the eight sign
|
|
// faces as eight separate draw ops through consolidation, and
|
|
// the Winners Circle swaps the real callsign in later.
|
|
//
|
|
const char *base = strrchr(textureFilename, '\\');
|
|
base = (base != NULL) ? base + 1 : textureFilename;
|
|
int plate = 0;
|
|
if (_strnicmp(base, "player", 6) == 0 &&
|
|
base[6] >= '1' && base[6] <= '8')
|
|
{
|
|
plate = base[6] - '0';
|
|
}
|
|
|
|
if (plate != 0)
|
|
{
|
|
memset(&object->mDrawOps[i].texture, 0, sizeof(L4TEXOP));
|
|
object->mDrawOps[i].texture.texture =
|
|
NamePlateMarker(device, plate);
|
|
if (object->mDrawOps[i].texture.texture != NULL)
|
|
{
|
|
object->mDrawOps[i].texture.texture->AddRef();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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;
|
|
}
|
|
|
|
HRESULT hr = D3DXCreateTextureFromFileA(device, fileName, &texOp.texture);
|
|
if (FAILED(hr))
|
|
{
|
|
// texOp.texture stays NULL (memset above); draw ops render untextured,
|
|
// matching the "no texture filename" path in LoadObject.
|
|
DEBUG_STREAM << "L4D3D.cpp couldn't load texture " << fileName << " (hr=0x" << std::hex << hr << std::dec << ")\n" << std::flush;
|
|
}
|
|
|
|
mTextureCache.insert(std::pair<std::string,L4TEXOP>(std::string(fileName), texOp));
|
|
}
|
|
else
|
|
texOp = mTextureCache[std::string(fileName)];
|
|
|
|
if (texOp.texture != NULL)
|
|
texOp.texture->AddRef();
|
|
return texOp;
|
|
}
|
|
|
|
void d3d_OBJECT::FlushTextureCache()
|
|
{
|
|
stdext::hash_map<std::string, L4TEXOP>::iterator iter;
|
|
for (iter = mTextureCache.begin(); iter != mTextureCache.end(); ++iter)
|
|
{
|
|
if ((*iter).second.texture != NULL)
|
|
(*iter).second.texture->Release();
|
|
}
|
|
mTextureCache.clear();
|
|
|
|
for (int plate = 0; plate <= kNamePlateCount; ++plate)
|
|
{
|
|
if (mNamePlateMarkers[plate] != NULL)
|
|
{
|
|
mNamePlateMarkers[plate]->Release();
|
|
mNamePlateMarkers[plate] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// A distinct 1x1 texture per plate, so the eight sign faces stay eight
|
|
// separate draw ops through mesh consolidation instead of merging into one.
|
|
// Its content never shows - the callsign replaces it before the podium.
|
|
//
|
|
LPDIRECT3DTEXTURE9 d3d_OBJECT::NamePlateMarker(LPDIRECT3DDEVICE9 device, int plate)
|
|
{
|
|
if (plate < 1 || plate > kNamePlateCount || device == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
if (mNamePlateMarkers[plate] == NULL)
|
|
{
|
|
device->CreateTexture(1, 1, 1, 0, D3DFMT_A4R4G4B4, D3DPOOL_MANAGED,
|
|
&mNamePlateMarkers[plate], NULL);
|
|
}
|
|
return mNamePlateMarkers[plate];
|
|
}
|
|
|
|
//
|
|
// Which plate a texture is the marker for, or 0 if it is not one.
|
|
//
|
|
int d3d_OBJECT::NamePlateFor(LPDIRECT3DTEXTURE9 texture)
|
|
{
|
|
if (texture == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
for (int plate = 1; plate <= kNamePlateCount; ++plate)
|
|
{
|
|
if (mNamePlateMarkers[plate] == texture)
|
|
{
|
|
return plate;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
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);
|
|
}
|
|
} |