Skip to content

Commit

Permalink
Gothic 1/2 polyStrips (weapon/projectile/spell trails) support.
Browse files Browse the repository at this point in the history
  • Loading branch information
kirides committed Dec 17, 2019
1 parent 14dcb3e commit 31f5735
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 247 deletions.
46 changes: 34 additions & 12 deletions D3D11Engine/D3D11GraphicsEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1613,10 +1613,12 @@ XRESULT D3D11GraphicsEngine::OnStartWorldRendering() {
// DrawParticleEffects();
Engine::GAPI->DrawParticlesSimple();

#if defined BUILD_GOTHIC_2_6_fix || defined BUILD_GOTHIC_1_08k
// Calc weapon/effect trail mesh data
Engine::GAPI->CalcPolyStripMeshes();
// Draw those
DrawPolyStrips();
#endif

// Draw debug lines
LineRenderer->Flush();
Expand Down Expand Up @@ -1774,10 +1776,8 @@ XRESULT D3D11GraphicsEngine::DrawMeshInfoListAlphablended(
SetDefaultStates();

// Setup renderstates
// changed CM_CULL_BACK to CM_CULL_NONE since i've noticed some flat models being rendered incorrectly (waterfall splashes for ex)
// Hopefully this will not screw up something else
Engine::GAPI->GetRendererState()->RasterizerState.CullMode = GothicRasterizerStateInfo::CM_CULL_NONE;

Engine::GAPI->GetRendererState()->RasterizerState.CullMode = GothicRasterizerStateInfo::CM_CULL_NONE;
Engine::GAPI->GetRendererState()->RasterizerState.SetDirty();

DirectX::SimpleMath::Matrix view;
Expand Down Expand Up @@ -3634,7 +3634,8 @@ XRESULT D3D11GraphicsEngine::DrawVOBs(bool noTextures) {
}

XRESULT D3D11GraphicsEngine::DrawPolyStrips(bool noTextures) {
std::list<PolyStripInfo> polyStripInfos = Engine::GAPI->GetPolyStripInfos();
//DrawMeshInfoListAlphablended was mostly used as an example to write everything below
std::map<zCTexture*, PolyStripInfo> polyStripInfos = Engine::GAPI->GetPolyStripInfos();

SetDefaultStates();

Expand All @@ -3658,17 +3659,23 @@ XRESULT D3D11GraphicsEngine::DrawPolyStrips(bool noTextures) {
ActivePS->GetConstantBuffer()[0]->UpdateBuffer(&Engine::GAPI->GetRendererState()->GraphicsState);
ActivePS->GetConstantBuffer()[0]->BindToPixelShader(0);

// Not sure what this does, adds some kind of sky tint?
GSky* sky = Engine::GAPI->GetSky();
ActivePS->GetConstantBuffer()[1]->UpdateBuffer(&sky->GetAtmosphereCB());
ActivePS->GetConstantBuffer()[1]->BindToPixelShader(1);

// Use default material info for now
MaterialInfo defInfo;
ActivePS->GetConstantBuffer()[2]->UpdateBuffer(&defInfo);
ActivePS->GetConstantBuffer()[2]->BindToPixelShader(2);

for (auto it = polyStripInfos.begin(); it != polyStripInfos.end(); it++) {

zCMaterial* mat = it->second.material;
zCTexture* tx = mat->GetAniTexture();
std::vector<ExVertexStruct> vertices = it->second.vertices;

for (std::list<PolyStripInfo>::iterator it = polyStripInfos.begin(); it != polyStripInfos.end(); it++) {
zCMaterial* mat = it->material;
MeshInfo* mi = it->meshInfo;
zCVob* vob = it->vob;
if (!vertices.size()) continue;

//Setting world transform matrix/////////////
Matrix id = Matrix::Identity;
Expand All @@ -3677,8 +3684,6 @@ XRESULT D3D11GraphicsEngine::DrawPolyStrips(bool noTextures) {
ActiveVS->GetConstantBuffer()[1]->UpdateBuffer(&id);
ActiveVS->GetConstantBuffer()[1]->BindToVertexShader(1);

zCTexture* tx = mat->GetAniTexture();

// Check for alphablending on world mesh
bool blendAdd = mat->GetAlphaFunc() == zMAT_ALPHA_FUNC_ADD;
bool blendBlend = mat->GetAlphaFunc() == zMAT_ALPHA_FUNC_BLEND;
Expand Down Expand Up @@ -3719,10 +3724,27 @@ XRESULT D3D11GraphicsEngine::DrawPolyStrips(bool noTextures) {
info->UpdateConstantbuffer();

info->Constantbuffer->BindToPixelShader(2);

} else {
//Don't draw if texture is not yet cached (I have no idea how can I preload it in advance)
continue;
}

//Populate TempVertexBuffer and draw it
D3D11_BUFFER_DESC desc;
TempVertexBuffer->GetVertexBuffer()->GetDesc(&desc);
if (desc.ByteWidth < sizeof(ExVertexStruct) * vertices.size())
{
LogInfo() << "(PolyStrip) TempVertexBuffer too small (" << desc.ByteWidth << "), need " << sizeof(ExVertexStruct) * vertices.size() << " bytes. Recreating buffer.";

// Buffer too small, recreate it
TempVertexBuffer.reset(new D3D11VertexBuffer());
// Reinit with a bit of a margin, so it will not be reinit each time new vertex is added
TempVertexBuffer->Init(NULL, sizeof(ExVertexStruct) * vertices.size() * 1.1, D3D11VertexBuffer::B_VERTEXBUFFER, D3D11VertexBuffer::U_DYNAMIC, D3D11VertexBuffer::CA_WRITE);
}

// Draw batch // Should i use some other drawing method maybe, since I don't really have a "batch"?
DrawInstanced(mi->MeshVertexBuffer, mi->MeshIndexBuffer, mi->Indices.size(), DynamicInstancingBuffer.get(), sizeof(VobInstanceInfo), 1, sizeof(ExVertexStruct), 0);
TempVertexBuffer->UpdateBuffer(&vertices[0], sizeof(ExVertexStruct) * vertices.size());
DrawVertexBuffer(TempVertexBuffer.get(), vertices.size(), sizeof(ExVertexStruct));
}

SetDefaultStates();
Expand Down
158 changes: 50 additions & 108 deletions D3D11Engine/GothicAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -769,80 +769,79 @@ void GothicAPI::CalcPolyStripMeshes() {

PolyStripInfos.clear();

for (std::list<zCVob*>::iterator it = PolyStripVobs.begin(); it != PolyStripVobs.end(); it++) {
zCVob* vob = *it;
zCPolyStrip* pStrip = (zCPolyStrip*)(vob->GetVisual());
for (auto it = PolyStripVisuals.begin(); it != PolyStripVisuals.end(); it++) {
zCPolyStrip* pStrip = *it;

if (!pStrip) return;

std::unordered_map<int, PolyStripSegmentInfo>* segmentsInfo = &PolyStripSegmentInfos[pStrip];

//Was unalbe to find original starting alpha in instance params. Fade-out easing type used is also unknown.
//therefore these params are not precise, they just "feel" right.
float startAlpha = 0.35;
float fadeSpeedMult = 1.5;
//Pointer passed is a placeholder, it'll not be used inside the function.
//We need gothic engine to only execute relevant calculations inside native Render()
//without actually rendering polygons. Inside Render() polygons are rendered
//with zCRnd_D3D::DrawPoly(). Hook created inside zCRndD3D.h prevents native rendering.
pStrip->Render(pStrip);
//////////////////////////////

zCPolyStripInstance pStripInst = pStrip->GetInstanceData();

if (pStripInst.camAlign == 1) pStrip->AlighToCamera();
zCMaterial* mat = pStripInst.material;
zCTexture* tx = mat->GetAniTexture();

//These values go back to 0 after reaching maxSegAmount
int firstSeg = pStripInst.firstSeg;
int lastSeg = pStripInst.lastSeg;
int maxSegAmount = pStripInst.numVert / 2;

int newFirstSeg = firstSeg;

float* alphaList = pStripInst.alphaList;
zCVertex* vertList = pStripInst.vertList;
zCPolygon* poly = &(pStripInst.polyList[0]);


std::vector<ExVertexStruct> vertices;
std::vector<VERTEX_INDEX> indices;

//order of vertex indeces that make up a single poly
int vertOrder[4] = { 0, 1, 3, 2 };


//Loop though segment while allowing segment index to overflow maxSegAmount
for (int i = firstSeg; ; i++) {
int segIndex = i % maxSegAmount;
std::vector<ExVertexStruct> polyFan;


//Animating segments fade out////
if (segmentsInfo->find(segIndex) == segmentsInfo->end()) {
segmentsInfo->operator[](segIndex).createdAt = std::chrono::steady_clock::now();
if (segIndex == lastSeg) {
//Triangles for the last segment are created during previous iteration, so break here.
break;
}

auto now = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - segmentsInfo->operator[](segIndex).createdAt);
unsigned int ms = elapsed.count();
std::vector<ExVertexStruct> polyFan;

float alphaFrac = startAlpha - (pStripInst.alphaFadeSpeed * fadeSpeedMult * (ms / 1000.0)); //think in original it's not a linear fade-out
if (alphaFrac <= 0) {
alphaFrac = 0;
//Make faded-out segment a first one in polyStrip, previous segments will be cleaned up.
newFirstSeg = segIndex;
}
/////////////////////////////////
#ifdef BUILD_GOTHIC_1_08k
//For G1 vertices are taken from polygons in polyList
poly = &pStripInst.polyList[segIndex];
zCVertex** polyVertices = poly->getVertices();

for (int n = 0; n < 4; n++) {
ExVertexStruct vert;

if (segIndex == lastSeg) {
//Triangles for the last segment are created during previous iteration, so break here.
break;
vert.Position = polyVertices[n]->Position;
vert.TexCoord = poly->getFeatures()[n]->texCoord;
vert.Normal = poly->getFeatures()[n]->normal;
vert.Color = poly->getFeatures()[n]->lightStatic;

polyFan.push_back(vert);
}


#endif
#ifdef BUILD_GOTHIC_2_6_fix
//For G2 polyList only contains a single polygon (supposed to be kind of a reference it seems)
//and vertices should be taken from vertList, while preserving a correct order making up a
//properly winded polygon
for (int n = 0; n < 4; n++) {
//In similar fashion to segment index - vertex index should overflow numVert
//In similar fashion to segment index - vertex index should overflow numVert.
int vInd = (segIndex * 2 + vertOrder[n]) % pStripInst.numVert;
//Segment index of the current vertex (it's not always equals `i` since we loop through next segment's vertices as well).
int vSegInd = ((segIndex * 2 + vertOrder[n]) / 2) % maxSegAmount;

ExVertexStruct vert;

vert.Position = vertList[vInd].Position;

//Vertex features are hooked up from reference polygon's vertices
vert.TexCoord = poly->getFeatures()[n]->texCoord;
vert.Normal = poly->getFeatures()[n]->normal;
Expand All @@ -851,81 +850,22 @@ void GothicAPI::CalcPolyStripMeshes() {
//Applying current segment alpha values//
uint8_t color[4];
memcpy(&color, &vert.Color, 4);
color[3] = 255 * alphaFrac;
float alpha = alphaList[vSegInd];
if (alpha < 0) alpha = 0;
color[3] = alpha;
memcpy(&vert.Color, &color, 4);
/////////////////////////////////////////
polyFan.push_back(vert);
}
#endif

if (!polyFan.empty()) {
//Convert list of quads to list of triangles
WorldConverter::TriangleFanToList(&polyFan[0], polyFan.size(), &vertices);
WorldConverter::TriangleFanToList(&polyFan[0], polyFan.size(), &PolyStripInfos[tx].vertices);
PolyStripInfos[tx].material = mat;
}
}

if (!vertices.size()) continue;

//building naive unoptimized index array based on vertices
for (int i = 0; i < vertices.size(); i++)
{
indices.push_back(i);
}

MeshInfo* mi = new MeshInfo;

mi->Vertices = vertices;
mi->Indices = indices;

// Create the buffers
Engine::GraphicsEngine->CreateVertexBuffer(&mi->MeshVertexBuffer);
Engine::GraphicsEngine->CreateVertexBuffer(&mi->MeshIndexBuffer);

// Generate normals
WorldConverter::GenerateVertexNormals(mi->Vertices, mi->Indices);

// Optimize faces and vertices (No idea what this does tbh)
mi->MeshVertexBuffer->OptimizeFaces(&mi->Indices[0],
(byte*)&mi->Vertices[0],
mi->Indices.size(),
mi->Vertices.size(),
sizeof(ExVertexStruct));

mi->MeshVertexBuffer->OptimizeVertices(&mi->Indices[0],
(byte*)&mi->Vertices[0],
mi->Indices.size(),
mi->Vertices.size(),
sizeof(ExVertexStruct));


// Init and fill buffers
mi->MeshVertexBuffer->Init(&mi->Vertices[0], mi->Vertices.size() * sizeof(ExVertexStruct), D3D11VertexBuffer::B_VERTEXBUFFER, D3D11VertexBuffer::U_IMMUTABLE);
mi->MeshIndexBuffer->Init(&mi->Indices[0], mi->Indices.size() * sizeof(VERTEX_INDEX), D3D11VertexBuffer::B_INDEXBUFFER, D3D11VertexBuffer::U_IMMUTABLE);

zCMaterial* mat = pStrip->GetMaterial();

PolyStripInfo polyStripInfo;
polyStripInfo.material = mat;
polyStripInfo.meshInfo = mi;
polyStripInfo.vob = vob;

PolyStripInfos.push_back(polyStripInfo);

//Define visible segments range using newFirstSeg set above based on segments alpha.
//Gothic engine cleans up (reuses) all the segments not in visible range.
//It seems that first segment fraction should always be a tad smaller than lastSeg fraction
//even if it's the same segment index, hence +.001 is used. Otherwise if you are attempting to
//set first and last segment to the same index (i.e when all segments disappeared) engine will, for some reason,
//assume that you actually want to set all segments to be visible.
if (newFirstSeg != firstSeg) {
pStrip->SetVisibleSegments(newFirstSeg / (maxSegAmount + .001), lastSeg / float(maxSegAmount));
//cleanup segment infos which are not in range
for (int i = lastSeg + 1; ; i++) {
int segIndex = i % maxSegAmount;
int firstSeg = (newFirstSeg + maxSegAmount - 1) % maxSegAmount;
if (segIndex == firstSeg) break;
segmentsInfo->erase(segIndex);
}

}
}
};

Expand Down Expand Up @@ -1077,10 +1017,9 @@ void GothicAPI::OnVisualDeleted(zCVisual * visual) {

// This is a poly strip vob
if (strcmp(className, "zCPolyStrip") == 0) {
for (std::list<zCVob*>::iterator it = PolyStripVobs.begin(); it != PolyStripVobs.end(); it++) {
if ((*it)->GetVisual() == visual) {
PolyStripVobs.remove(*it);
PolyStripSegmentInfos.erase((zCPolyStrip*)visual);
for (auto it = PolyStripVisuals.begin(); it != PolyStripVisuals.end(); it++) {
if (*it == (zCPolyStrip*)visual) {
PolyStripVisuals.erase(*it);
}
}
}
Expand Down Expand Up @@ -1207,8 +1146,7 @@ void GothicAPI::OnRemovedVob(zCVob * vob, zCWorld * world) {
zCClassDef* classDef = ((zCObject*)(visual))->_GetClassDef();
const char* className = classDef->className.ToChar();
if (strcmp(className, "zCPolyStrip") == 0) {
PolyStripVobs.remove(vob); //remove it if it exists in polystrips array
PolyStripSegmentInfos.erase((zCPolyStrip*)visual);
PolyStripVisuals.erase((zCPolyStrip*)visual); //remove it if it exists in polystrips array
}
}

Expand Down Expand Up @@ -1418,7 +1356,7 @@ void GothicAPI::OnAddVob(zCVob * vob, zCWorld * world) {
world = oCGame::GetGame()->_zCSession_world;

if (strcmp(className, "zCPolyStrip") == 0) {
PolyStripVobs.push_back(vob);
PolyStripVisuals.insert((zCPolyStrip*)(vob->GetVisual()));
}

for (unsigned int i = 0; i < extv.size(); i++) {
Expand Down Expand Up @@ -1902,6 +1840,10 @@ void GothicAPI::DrawParticleFX(zCVob * source, zCParticleFX * fx, ParticleFrameD
break;
}

if (p->PolyStrip) {
PolyStripVisuals.insert(p->PolyStrip);
};

// Generate instance info
ParticleInstanceInfo ii;
ii.scale = Vector2(p->Size.x, p->Size.y);
Expand Down
13 changes: 5 additions & 8 deletions D3D11Engine/GothicAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ struct ParticleFrameData {

struct PolyStripInfo
{
MeshInfo* meshInfo;
std::vector<ExVertexStruct> vertices;
zCMaterial* material;
zCVob* vob;
};
Expand Down Expand Up @@ -538,7 +538,7 @@ class GothicAPI {
const std::unordered_map<zCProgMeshProto *, MeshVisualInfo *> & GetStaticMeshVisuals() { return StaticMeshVisuals; }

/** Returns the collection of PolyStrip meshes infos */
const std::list<PolyStripInfo>& GetPolyStripInfos() { return PolyStripInfos; };
const std::map<zCTexture*, PolyStripInfo>& GetPolyStripInfos() { return PolyStripInfos; };

/** Removes the given texture from the given section and stores the supression, so we can load it next time */
void SupressTexture(WorldMeshSectionInfo * section, const std::string & texture);
Expand Down Expand Up @@ -682,11 +682,8 @@ class GothicAPI {
std::list<zCVob *> DecalVobs;
std::unordered_map<zCVob *, std::string> tempParticleNames;

/** Poly strip segment infos (mostly their alpha values)**/
std::unordered_map<zCPolyStrip*, std::unordered_map<int, PolyStripSegmentInfo>> PolyStripSegmentInfos;

/** Poly strip Vobs */
std::list<zCVob*> PolyStripVobs;
/** Poly strip Visuals */
std::set<zCPolyStrip*> PolyStripVisuals;

/** Set of Materials */
std::set<zCMaterial *> LoadedMaterials;
Expand All @@ -698,7 +695,7 @@ class GothicAPI {
std::unordered_map<zCProgMeshProto *, MeshVisualInfo *> StaticMeshVisuals;

/** Collection of poly strip infos (includes mesh and material data) */
std::list<PolyStripInfo> PolyStripInfos;
std::map<zCTexture*, PolyStripInfo> PolyStripInfos;

/** Map for skeletal mesh visuals */
std::unordered_map<std::string, SkeletalMeshVisualInfo *> SkeletalMeshVisuals;
Expand Down
Loading

0 comments on commit 31f5735

Please sign in to comment.