WMO/Rendering

From wowdev
Revision as of 05:19, 5 October 2017 by Fallenoak (talk | contribs) (→‎Lighting: Add initial reversal of CMapObjGroup::QueryLighting)
Jump to navigation Jump to search

Lighting

Lighting for interior WMO groups is prebaked into vertex colors.

CMapObj::QueryLighting

In order to light entities like units, game objects, etc that exist within interior WMO groups, the game does the following:

  1. Query for the closest MOPY.
  2. Obtain the 3 relevant MOCV values for the MOPY.
  3. Create a CImVector color by interpolating the values based on the position of the entity relative to the MOPY (ie barycentric interpolation).

This queried color value is then fed in to the standard lighting logic.

Query with C3Segment

The following function is used to query lighting when the exact poly is not yet known. It uses a C3Segment to perform a ranged query against the BSP tree for relevant tris.

bool CMapObj::QueryLighting(CMapObj *this, uint32_t groupIndex, const C3Segment *seg, CImVector *color, bool *a5) {

  CMapObjGroup group = this->groupList[groupIndex];

  if (!this->unk6[16] || !(group->unk14 & 1) || group->flags & (SMOGroup::EXTERIOR | SMOGroup::EXTERIOR_LIT)) {

    return 0;

  }

  World::TriData::resultFlags = 0;
  World::TriData::nBatches = 0;
  World::TriData::nTriIndices = 0;
  World::TriData::nVertexIndices = 0;
  World::TriData::nMatrices = 0;

  float hitT = 1.0;

  // Query the BSP tree for the group to find appropriate tris

  bool triRes = CMapObjGroup::GetTris(group, seg, &hitT, 0, 0x8, (int)&a2 + 3, 0);

  if (!triRes) {

    return 0;

  }

  // Obtain point matching intersection between segment and tri

  C3Vector point;

  point.x = seg->start.x + hitT * (seg->end.x - seg->start.x);
  point.y = seg->start.y + hitT * (seg->end.y - seg->start.y);
  point.z = seg->start.z + hitT * (seg->end.z - seg->start.z);

  unsigned __int16 hitPoly = word_CD8094;

  bool lightRes = CMapObjGroup::QueryLighting(group, &point, hitPoly, color, a5);

  return lightRes;

}

Query with C3Vector and poly index

The following function is used to query lighting when the relevant poly is already known.

bool CMapObj::QueryLighting(CMapObj *this, uint32_t groupIndex, const C3Vector *point, uint16_t polyIdx, CImVector *color, bool *a5) {

  CMapObjGroup group = this->groupList[groupIndex];

  if (!this->unk6[16] || !(group->unk14 & 1) || group->flags & (SMOGroup::EXTERIOR | SMOGroup::EXTERIOR_LIT)) {

    return 0;

  }

  // Since the point and poly are already known, there's no need to query the BSP tree

  bool lightRes = CMapObjGroup::QueryLighting(group, point, polyIdx, color, a5);

  return lightRes;

}

CMapObjGroup::QueryLighting

char CMapObjGroup::QueryLighting(CMapObjGroup *this, const C3Vector *point, unsigned __int16 polyIdx, CImVector *color, bool *a5) {

  bool v5; // cf@1
  char result; // al@2
  unsigned __int16 *indices; // esi@5
  C3Vector *vertices; // eax@5
  C3Vector *vert1; // edi@5
  C3Vector *vert2; // ebx@5
  double v11; // st7@5
  double v12; // st6@5
  double v13; // st5@5
  double v14; // st4@5
  double v15; // st3@5
  double v16; // st2@5
  signed int v17; // eax@5
  int v18; // ecx@5
  int v19; // eax@5
  int v20; // ecx@5
  double v21; // st5@5
  double v22; // st4@5
  double v23; // st2@5
  double v24; // st3@5
  double v25; // st7@5
  double v26; // st5@5
  double v27; // st6@5
  double v28; // st1@5
  double v29; // st7@5
  double v30; // st0@5
  signed int v31; // edi@5
  double v32; // st7@5
  int v33; // edx@5
  int v34; // ecx@5
  int v35; // eax@6
  int v36; // eax@8
  int v37; // eax@10
  CMapObjGroup *v38; // eax@11
  CImVector *v39; // ebx@11
  int v40; // eax@11
  int v41; // edi@11
  int v42; // ecx@11
  int v43; // esi@11
  int v44; // eax@11
  CMapObjGroup *v45; // edi@11
  signed int v46; // eax@11
  int v47; // ecx@11
  CMapObj *v48; // edi@11
  unsigned int v49; // ecx@11
  unsigned int v50; // esi@11
  unsigned int v51; // eax@11
  unsigned __int8 v52; // cl@15
  C3Vector v53; // [sp+0h] [bp-1Ch]@5
  float v54; // [sp+10h] [bp-Ch]@5
  C3Vector *vert3; // [sp+14h] [bp-8h]@5
  CMapObjGroup *v56; // [sp+18h] [bp-4h]@1
  const C3Vector *pointb; // [sp+24h] [bp+8h]@5
  int pointa; // [sp+24h] [bp+8h]@5

  v5 = polyIdx < this->polyCount;
  v56 = this;

  if ( v5 )
  {
    if ( !(dword_D2DC18 & 1) )
    {
      dword_D2DC18 |= 1u;
      xyAxisTable[0].y = 2;
      xyAxisTable[1].x = 2;
      xyAxisTable[0].x = 1;
      xyAxisTable[1].y = 0;
      xyAxisTable[2].x = 0;
      xyAxisTable[2].y = 1;
    }
    indices = &this->indexList[3 * polyIdx];
    vertices = this->vertexList;
    vert1 = &vertices[*indices];
    vert2 = &vertices[indices[1]];
    vert3 = &vertices[indices[2]];
    v11 = vert3->x - vert1->x;
    v12 = vert3->y - vert1->y;
    v13 = vert3->z - vert1->z;
    v14 = vert2->x - vert1->x;
    v15 = vert2->y - vert1->y;
    v16 = vert2->z - vert1->z;
    v53.x = v15 * v13 - v16 * v12;
    v53.y = v16 * v11 - v13 * v14;
    v53.z = v12 * v14 - v11 * v15;
    v17 = C3Vector::MajorAxis(&v53);
    v18 = 8 * v17 + 0xD2DC00;
    v19 = 4 * xyAxisTable[v17].x;
    v20 = 4 * *(_DWORD *)(v18 + 4);
    v21 = *(float *)((char *)&vert1->x + v19);
    v22 = *(float *)((char *)&vert1->x + v20);
    v23 = *(float *)((char *)&vert2->x + v19) - v21;
    v24 = *(float *)((char *)&vert3->x + v19) - v21;
    v25 = *(float *)((char *)&vert3->x + v20) - v22;
    v26 = *(float *)((char *)&point->x + v19) - v21;
    v27 = *(float *)((char *)&vert2->x + v20) - v22;
    v28 = v25;
    v29 = 1.0 / (v25 * v23 - v27 * v24);
    v30 = *(float *)((char *)&point->x + v20) - v22;
    v54 = v29 * (v23 * v30 - v26 * v27);
    *(float *)&vert3 = (v28 * v26 - v24 * v30) * v29 * 256.0;
    v31 = (signed int)(*(float *)&vert3 - flt_AEEE50);
    *(float *)&pointb = v54 * 256.0;
    v32 = *(float *)&pointb - flt_AEEE50;
    vert3 = (C3Vector *)(signed int)v32;
    v33 = (signed int)v32;
    v34 = 256 - (signed int)v32 - v31;
    pointa = (signed int)v32;
    if ( v31 < 0 )
    {
      v35 = v31 * v33 / (v33 + v34);
      v33 = (int)vert3 + v35;
      v34 += v31 - v35;
      pointa = (int)vert3 + v35;
      v31 = 0;
    }
    if ( v33 < 0 )
    {
      v36 = v31 * v33 / (v34 + v31);
      v31 += v36;
      v34 += pointa - v36;
      v33 = 0;
      pointa = 0;
    }
    if ( v34 < 0 )
    {
      v37 = v31 * v34 / (v33 + v31);
      pointa += v34 - v37;
      v31 += v37;
      v34 = 0;
    }
    color->a = (unsigned __int16)(pointa * v56->colorVertexList[indices[2]].a
                                + v34 * v56->colorVertexList[*indices].a
                                + v31 * v56->colorVertexList[indices[1]].a) >> 8;
    color->r = (unsigned __int16)(pointa * v56->colorVertexList[indices[2]].r
                                + v34 * v56->colorVertexList[*indices].r
                                + v31 * v56->colorVertexList[indices[1]].r) >> 8;
    v38 = v56;
    color->g = (unsigned __int16)(pointa * v56->colorVertexList[indices[2]].g
                                + v34 * v56->colorVertexList[*indices].g
                                + v31 * v56->colorVertexList[indices[1]].g) >> 8;
    v39 = v38->colorVertexList;
    v40 = v31 * v39[indices[1]].b;
    v41 = v34 * v39[*indices].b;
    v42 = pointa * v39[indices[2]].b;
    v43 = color->g;
    v44 = v41 + v40;
    v45 = v56;
    v46 = v42 + v44;
    v47 = color->r;
    v46 >>= 8;
    color->b = v46;
    v48 = v45->parent;
    v49 = 2 * v47;
    v50 = 2 * v43;
    v51 = 2 * (unsigned __int8)v46;
    if ( v48->header->flags & 2 )
    {
      v49 += v48->ambColor.r;
      v50 += v48->ambColor.g;
      v51 += v48->ambColor.b;
    }
    if ( v49 >= 0xFF )
      LOBYTE(v49) = -1;
    color->r = v49;
    v52 = v50;
    if ( v50 >= 0xFF )
      v52 = -1;
    color->g = v52;
    if ( v51 >= 0xFF )
      LOBYTE(v51) = -1;
    color->b = v51;
    *a5 = v56->polyList[polyIdx].flags & 1;
    result = 1;
  }
  else
  {
    *color = this->parent->ambColor;
    *a5 = 0;
    result = 1;
  }

  return result;

}