changeset 196:982c1ec5a983

More picking stuff
author Nomad
date Sat, 16 Feb 2013 20:24:02 +0200
parents 3dfa006a6bef
children 5979fc0de9ae
files Vis.cpp Vis.h mm7_2.cpp mm7_data.h
diffstat 4 files changed, 234 insertions(+), 353 deletions(-) [+]
line wrap: on
line diff
--- a/Vis.cpp	Sat Feb 16 18:34:31 2013 +0200
+++ b/Vis.cpp	Sat Feb 16 20:24:02 2013 +0200
@@ -23,29 +23,29 @@
 
 
 //----- (004C1026) --------------------------------------------------------
-Vis_ObjectInfo *Vis::_4C1026(BLVFace *a2, unsigned int a3, float a4)
+Vis_ObjectInfo *Vis::_4C1026(BLVFace *face, unsigned int a3, float pick_depth)
 {
   char *v4; // eax@4
   signed int v5; // ecx@4
-  BLVFace *v6; // ecx@7
-  unsigned int v7; // edi@7
+  //BLVFace *v6; // ecx@7
+  //unsigned int v7; // edi@7
   Vec3_short_ *v8; // eax@9
   char *v9; // edx@9
   signed int v10; // esi@10
-  Vec3_int_ **v11; // edx@13
-  char *v12; // eax@13
-  double v13; // st7@14
-  signed int v14; // ebx@14
-  Vis *v15; // ebx@15
-  Vis_ObjectInfo *result; // eax@21
-  Vis_ObjectInfo *v17; // ecx@24
+  //Vec3_int_ **v11; // edx@13
+  //char *v12; // eax@13
+  //double v13; // st7@14
+  //signed int v14; // ebx@14
+  //Vis *v15; // ebx@15
+  //Vis_ObjectInfo *result; // eax@21
+  //Vis_ObjectInfo *v17; // ecx@24
   RenderVertexSoft pRay[2]; // [sp+20h] [bp-70h]@17
   int v20; // [sp+84h] [bp-Ch]@10
-  int v21; // [sp+88h] [bp-8h]@16
-  int v22; // [sp+8Ch] [bp-4h]@16
+  //int v21; // [sp+88h] [bp-8h]@16
+  //int v22; // [sp+8Ch] [bp-4h]@16
   signed int v23; // [sp+98h] [bp+8h]@7
 
-  auto ecx0 = this;
+  //auto ecx0 = this;
 
   static Vis_SelectionList static_sub_4C1026_stru_F8FE00;
   static_sub_4C1026_stru_F8FE00.uNumPointers = 0;
@@ -59,138 +59,150 @@
       static_sub_4C1026_array_F8F200[i].flt_2C = 0.0f;
   }
 
-  v6 = a2;
+  //v6 = a2;
   v23 = 0;
-  v7 = v6->uNumVertices;
-  if ( uCurrentlyLoadedLevelType == LEVEL_Indoor )
+  //v7 = face->uNumVertices;
+  if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
   {
-    if ( (signed int)v7 > 0 )
+    __debugbreak(); // refactor for BLV picking
+    if ( (signed int)face->uNumVertices > 0 )
     {
       v8 = pIndoor->pVertices;
       v9 = (char *)&static_sub_4C1026_array_F8F200[0].vWorldPosition.y;
       do
       {
         v10 = v23++;
-        v20 = v8[v6->pVertexIDs[v10]].x;
+        v20 = v8[face->pVertexIDs[v10]].x;
         *((float *)v9 - 1) = (double)v20;
-        v20 = v8[v6->pVertexIDs[v10]].y;
+        v20 = v8[face->pVertexIDs[v10]].y;
         *(float *)v9 = (double)v20;
         v9 += 48;
-        v20 = v8[v6->pVertexIDs[v10]].z;
+        v20 = v8[face->pVertexIDs[v10]].z;
         *((float *)v9 - 11) = (double)v20;
       }
-      while ( v23 < (signed int)v7 );
+      while ( v23 < (signed int)face->uNumVertices );
+    }
+  }
+  else if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
+  {
+    uint bmodel_id = a3 >> 9;
+    auto v = (Vec3_int_ *)pOutdoor->pBModels[bmodel_id].pVertices.pVertices;
+    for (uint i = 0; i < face->uNumVertices; ++i)
+    {
+      static_sub_4C1026_array_F8F200[i].vWorldPosition.x = v[face->pVertexIDs[i]].x;
+      static_sub_4C1026_array_F8F200[i].vWorldPosition.y = v[face->pVertexIDs[i]].y;
+      static_sub_4C1026_array_F8F200[i].vWorldPosition.z = v[face->pVertexIDs[i]].z;
     }
   }
-  else
-  {
-    if ( (signed int)v7 > 0 )
-    {
-      v11 = &pOutdoor->pBModels[a3 >> 9].pVertices.pVertices;
-      v12 = (char *)&static_sub_4C1026_array_F8F200[0].vWorldPosition.y;
-      do
-      {
-        *((float *)v12 - 1) = (double)(*v11)[v6->pVertexIDs[v23]].x;
-        v13 = (double)(*v11)[v6->pVertexIDs[v23]].y;
-        v14 = v23++;
-        *(float *)v12 = v13;
-        v12 += 48;
-        *((float *)v12 - 11) = (double)(*v11)[v6->pVertexIDs[v14]].z;
-      }
-      while ( v23 < (signed int)v7 );
-    }
-  }
-  pGame->pIndoorCameraD3D->ViewTransform(static_sub_4C1026_array_F8F200, v7);
-  pGame->pIndoorCameraD3D->Project(static_sub_4C1026_array_F8F200, v7, 1);
-  v15 = this;
-  SortVectors_x(static_sub_4C1026_array_F8F200, 0, v7 - 1);
-  if ( static_sub_4C1026_array_F8F200[0].vWorldViewPosition.x > (double)a4
-    || (_4C1495(static_sub_4C1026_array_F8F200, v7, (float *)&v21, (float *)&v22),
-        _4C12C3_FindSomeBillboard(static_sub_4C1026_array_F8F200, v7, *(float *)&v21, *(float *)&v22))
-    || ((CastPickRay(pRay, *(float *)&v21, *(float *)&v22, a4), uCurrentlyLoadedLevelType != LEVEL_Indoor) ? PickOutdoor(a4, pRay, &static_sub_4C1026_stru_F8FE00, &vis_face_filter, 1) : PickIndoor(a4, pRay, &static_sub_4C1026_stru_F8FE00, &vis_face_filter),
-        (static_sub_4C1026_stru_F8FE00.create_object_pointers(Vis_SelectionList::All),
-         sort_object_pointers(
-           static_sub_4C1026_stru_F8FE00.object_pointers,
-           0,
-           static_sub_4C1026_stru_F8FE00.uNumPointers - 1),
-         !static_sub_4C1026_stru_F8FE00.uNumPointers)
-     || (result = static_sub_4C1026_stru_F8FE00.sub_4C2551(2, a3)) == 0
-     || (signed int)static_sub_4C1026_stru_F8FE00.uNumPointers > 1
-     && ((signed int)static_sub_4C1026_stru_F8FE00.uNumPointers <= 0 ? (v17 = 0) : (v17 = static_sub_4C1026_stru_F8FE00.object_pointers[0]),
-         result != v17)) )
-    result = 0;
-  return result;
+  else assert(false);
+
+  pGame->pIndoorCameraD3D->ViewTransform(static_sub_4C1026_array_F8F200, face->uNumVertices);
+  pGame->pIndoorCameraD3D->Project(static_sub_4C1026_array_F8F200, face->uNumVertices, 1);
+
+  //v15 = this;
+  SortVectors_x(static_sub_4C1026_array_F8F200, 0, face->uNumVertices - 1);
+  if (static_sub_4C1026_array_F8F200[0].vWorldViewPosition.x > pick_depth)
+    return nullptr;
+
+  float screenspace_center_x,
+        screenspace_center_y;
+  GetPolygonScreenSpaceCenter(static_sub_4C1026_array_F8F200, face->uNumVertices, &screenspace_center_x, &screenspace_center_y);
+  if (IsPolygonOccludedByBillboard(static_sub_4C1026_array_F8F200, face->uNumVertices, screenspace_center_x, screenspace_center_y))
+    return nullptr;
+
+  CastPickRay(pRay, screenspace_center_x, screenspace_center_y, pick_depth);
+
+  if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
+    PickOutdoorFaces_Mouse(pick_depth, pRay, &static_sub_4C1026_stru_F8FE00, &vis_face_filter, true);
+  else if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
+    PickIndoorFaces_Mouse(pick_depth, pRay, &static_sub_4C1026_stru_F8FE00, &vis_face_filter);
+  else assert(false);
+
+  static_sub_4C1026_stru_F8FE00.create_object_pointers();
+  sort_object_pointers(static_sub_4C1026_stru_F8FE00.object_pointers, 0, static_sub_4C1026_stru_F8FE00.uNumPointers - 1);
+  if (!static_sub_4C1026_stru_F8FE00.uNumPointers)
+    return nullptr;
+
+  if (!static_sub_4C1026_stru_F8FE00.sub_4C2551(2, a3))
+    return nullptr;
+
+  if (static_sub_4C1026_stru_F8FE00.uNumPointers)
+    return static_sub_4C1026_stru_F8FE00.object_pointers[0];
+  else return nullptr;
 }
 // F91E08: using guessed type char static_sub_4C1026_byte_F91E08__init_flags;
 
 //----- (004C12C3) --------------------------------------------------------
-char Vis::_4C12C3_FindSomeBillboard(RenderVertexSoft *a1, int a2, float a3, float a4)
+bool Vis::IsPolygonOccludedByBillboard(RenderVertexSoft *vertices, int num_vertices, float x, float y)
 {
-  signed int v5; // esi@1
-  RenderBillboardD3D *v6; // edi@2
-  double v7; // st7@9
-  int v8; // edx@9
-  RenderVertexSoft *v9; // ecx@10
-  char result; // al@24
-  Vis *thisa; // [sp+10h] [bp-8h]@1
-  float thisb; // [sp+10h] [bp-8h]@9
-  signed int v13; // [sp+14h] [bp-4h]@1
-  float a3a; // [sp+28h] [bp+10h]@9
-  float a4a; // [sp+2Ch] [bp+14h]@9
+  //signed int v5; // esi@1
+  //RenderBillboardD3D *v6; // edi@2
+  //double v7; // st7@9
+  //int v8; // edx@9
+  //RenderVertexSoft *v9; // ecx@10
+  //char result; // al@24
+  //Vis *thisa; // [sp+10h] [bp-8h]@1
+  //float thisb; // [sp+10h] [bp-8h]@9
+  //signed int v13; // [sp+14h] [bp-4h]@1
+  //float a3a; // [sp+28h] [bp+10h]@9
+  //float a4a; // [sp+2Ch] [bp+14h]@9
 
-  v13 = -1;
-  v5 = 0;
-  thisa = this;
-  if ( (signed int)pRenderer->uNumBillboardsToDraw <= 0 )
-  {
-    return 0;
-  }
-  v6 = pRenderer->pBillboardRenderListD3D;
-  do
-  {
-    if ( IsPointInsideD3DBillboard(v6, a3, a4)
-      && (v13 == -1
-	  || (unsigned int)pBillboardRenderList[v6->uParentBillboardID].sZValue < pBillboardRenderList[pRenderer->pBillboardRenderListD3D[v13].uParentBillboardID].sZValue) )
-      v13 = v5;
-    ++v5;
-    ++v6;
-  }
-  while ( v5 < (signed int)pRenderer->uNumBillboardsToDraw );
-  if ( v13 == -1 )
+  int v13 = -1;
+  //v5 = 0;
+  //thisa = this;
+
+  //v6 = pRenderer->pBillboardRenderListD3D;
+  for (uint i = 0; i < pRenderer->uNumBillboardsToDraw; ++i)
   {
-    return 0;
-  }
-  v7 = 3.4028235e38;
-  v8 = a2;
-  a4a = 3.4028235e38;
-  a3a = -3.4028235e38;
-  thisb = -3.4028235e38;
-  if ( a2 > 0 )
-  {
-    v9 = a1;
-    do
+    auto billboard = pRenderer->pBillboardRenderListD3D + i;
+    if (IsPointInsideD3DBillboard(billboard, x, y))
     {
-		if ( v9->vWorldViewProjX < v7 )
-			v7 = v9->vWorldViewProjX;
-		if ( v9->vWorldViewProjX > (double)a3a )
-        a3a = v9->vWorldViewProjX;
-		if ( v9->vWorldViewProjY < (double)a4a )
-        a4a = v9->vWorldViewProjY;
-      if ( v9->vWorldViewProjY > (double)thisb )
-        thisb = v9->vWorldViewProjY;
-      ++v9;
-      --v8;
+      if (v13 == -1)
+        v13 = i;
+      else  if ((unsigned int)pBillboardRenderList[billboard->uParentBillboardID].sZValue < pBillboardRenderList[pRenderer->pBillboardRenderListD3D[v13].uParentBillboardID].sZValue)
+        v13 = i;
     }
-    while ( v8 );
   }
-  if ( v7 < pRenderer->pBillboardRenderListD3D[v13].pQuards[0].pos.x
-    || pRenderer->pBillboardRenderListD3D[v13].pQuards[0].pos.y > (double)a4a
-    || pRenderer->pBillboardRenderListD3D[v13].pQuards[3].pos.x < (double)a3a
-    || pRenderer->pBillboardRenderListD3D[v13].pQuards[1].pos.y < (double)thisb )
-    result = 0;
-  else
-    result = 1;
-  return result;
+
+  if ( v13 == -1 )
+    return false;
+  
+  //v8 = num_vertices;
+  //v7 = 3.4028235e38;
+  float min_x = FLT_MAX;
+  //a4a = 3.4028235e38;
+  float min_y = FLT_MAX;
+  //a3a = -3.4028235e38;
+  float max_x = -FLT_MAX;
+  //thisb = -3.4028235e38;
+  float max_y = -FLT_MAX;
+  for (uint i = 0; i < num_vertices; ++i)
+  {
+    //v9 = a1;
+    //do
+    //{
+    auto v = vertices + i;
+
+    if (v->vWorldViewProjX < min_x)
+      min_x = v->vWorldViewProjX;
+    if (v->vWorldViewProjX > max_x)
+      max_x = v->vWorldViewProjX;
+
+    if (v->vWorldViewProjY < min_y)
+      min_y = v->vWorldViewProjY;
+    if (v->vWorldViewProjY > max_y)
+      max_y = v->vWorldViewProjY;
+      //++v9;
+      //--v8;
+    //}
+    //while ( v8 );
+  }
+
+  if (min_x < pRenderer->pBillboardRenderListD3D[v13].pQuards[0].pos.x || pRenderer->pBillboardRenderListD3D[v13].pQuards[0].pos.y > min_y ||
+      pRenderer->pBillboardRenderListD3D[v13].pQuards[3].pos.x < max_x || pRenderer->pBillboardRenderListD3D[v13].pQuards[1].pos.y < max_y)
+    return false;
+
+  return true;
 }
 
 //----- (004C1417) --------------------------------------------------------
@@ -208,38 +220,21 @@
 }
 
 //----- (004C1495) --------------------------------------------------------
-float *Vis::_4C1495(RenderVertexSoft *Src, int a2, float *a3, float *a4)
+void Vis::GetPolygonScreenSpaceCenter(RenderVertexSoft *vertices, int num_vertices, float *out_center_x, float *out_center_y)
 {
   char *v5; // eax@2
   signed int v6; // ecx@2
   float *result; // eax@5
-  Vis *thisa; // [sp+0h] [bp-4h]@1
 
-  thisa = this;
-
-  static bool static_sub_4C1495_byte_F8E9F8__init_flags = false; // weak
   static RenderVertexSoft static_sub_4C1495_array_F8DDF8[64];
-  if ( !static_sub_4C1495_byte_F8E9F8__init_flags )
-  {
-    static_sub_4C1495_byte_F8E9F8__init_flags = true;
 
-    for (uint i = 0; i < 64; ++i)
-      static_sub_4C1495_array_F8DDF8[i].flt_2C = 0.0f;
-  }
+  memcpy(static_sub_4C1495_array_F8DDF8, vertices, 48 * num_vertices);
 
-  memcpy(static_sub_4C1495_array_F8DDF8, Src, 48 * a2);
-  sort_objects_2(static_sub_4C1495_array_F8DDF8, 0, a2 - 1);
-  *a3 = (*(float *)&Vis_static_sub_4C1944_stru_F8BDE8.object_pointers[12 * a2 + 509]
-       - static_sub_4C1495_array_F8DDF8[0].vWorldViewProjX)
-      * 0.5
-      + static_sub_4C1495_array_F8DDF8[0].vWorldViewProjX;
-  sort_objects_3(static_sub_4C1495_array_F8DDF8, 0, a2 - 1);
-  result = a4;
-  *a4 = (*(float *)&Vis_static_sub_4C1944_stru_F8BDE8.object_pointers[12 * a2 + 510]
-       - static_sub_4C1495_array_F8DDF8[0].vWorldViewProjY)
-      * 0.5
-      + static_sub_4C1495_array_F8DDF8[0].vWorldViewProjY;
-  return result;
+  SortByScreenSpaceX(static_sub_4C1495_array_F8DDF8, 0, num_vertices - 1);
+  *out_center_x = (static_sub_4C1495_array_F8DDF8[num_vertices - 1].vWorldViewProjX - static_sub_4C1495_array_F8DDF8[0].vWorldViewProjX) * 0.5 + static_sub_4C1495_array_F8DDF8[0].vWorldViewProjX;
+
+  SortByScreenSpaceY(static_sub_4C1495_array_F8DDF8, 0, num_vertices - 1);
+  *out_center_y = (static_sub_4C1495_array_F8DDF8[num_vertices - 1].vWorldViewProjY - static_sub_4C1495_array_F8DDF8[0].vWorldViewProjY) * 0.5 + static_sub_4C1495_array_F8DDF8[0].vWorldViewProjY;
 }
 
 //----- (004C1542) --------------------------------------------------------
@@ -330,7 +325,7 @@
 }
 
 //----- (004C16B4) --------------------------------------------------------
-void Vis::PickIndoor(float fDepth, RenderVertexSoft *pRay, Vis_SelectionList *list, Vis_SelectionFilter *filter)
+void Vis::PickIndoorFaces_Mouse(float fDepth, RenderVertexSoft *pRay, Vis_SelectionList *list, Vis_SelectionFilter *filter)
 {
   int v5; // eax@1
   signed int v6; // edi@2
@@ -347,6 +342,8 @@
   int v17; // [sp+48h] [bp-8h]@1
   Vis *thisa; // [sp+4Ch] [bp-4h]@1
 
+  __debugbreak(); // refactor for BLV picking
+
   v5 = 0;
   thisa = this;
   v17 = 0;
@@ -388,99 +385,40 @@
 }
 
 //----- (004C17CF) --------------------------------------------------------
-void Vis::PickOutdoor(float fDepth, RenderVertexSoft *pRay, Vis_SelectionList *list, Vis_SelectionFilter *filter, char a6)
-{
-  int v6; // esi@1
-  unsigned int v7; // ecx@1
-  BSPModel *v8; // ebx@3
-  bool v9; // eax@3
-  int v10; // eax@8
-  ODMFace *v11; // esi@10
-  int v12; // ecx@12
-  int v13; // eax@12
-  unsigned int *pNumPointers; // eax@12
-  Vis_ObjectInfo *v15; // edi@12
-  BLVFace thisa; // [sp+10h] [bp-B8h]@1
-  RenderVertexSoft a1; // [sp+70h] [bp-58h]@1
-  void *v18; // [sp+A0h] [bp-28h]@12
-  void *v19; // [sp+A4h] [bp-24h]@12
-  int v20; // [sp+A8h] [bp-20h]@12
-  int v21; // [sp+ACh] [bp-1Ch]@8
-  Vis *v22; // [sp+B0h] [bp-18h]@1
-  int v23; // [sp+B4h] [bp-14h]@9
-  int v24; // [sp+B8h] [bp-10h]@1
-  unsigned int v25; // [sp+BCh] [bp-Ch]@2
-  unsigned int v26; // [sp+C0h] [bp-8h]@1
-  int v27; // [sp+C4h] [bp-4h]@8
-
-  v22 = this;
-  v6 = 0;
-  v7 = 0;
-  v24 = 0;
-  v26 = 0;
-  a1.flt_2C = 0.0;
+void Vis::PickOutdoorFaces_Mouse(float fDepth, RenderVertexSoft *pRay, Vis_SelectionList *list, Vis_SelectionFilter *filter, bool one_sided)
+{  
   if (!pOutdoor)
     return;
-  if ( (signed int)pOutdoor->uNumBModels > 0 )
+
+  for (uint i = 0; i < pOutdoor->uNumBModels; ++i)
   {
-    v25 = 0;
-    do
+    int v24;
+    if (!IsBModelVisible(i, &v24))
+      continue;
+    if (one_sided && !v24)
+      continue;
+
+    auto bmodel = &pOutdoor->pBModels[i];
+
+    for (uint j = 0; j < bmodel->uNumFaces; ++j)
     {
-      v8 = &pOutdoor->pBModels[v25 / 0xBC];
-      v9 = IsBModelVisible(v7, &v24);
-      if ( a6 )
+      auto face = bmodel->pFaces + j;
+      if (is_part_of_selection(face, filter))
       {
-        if ( v9 && v24 != v6 )
+        BLVFace blv_face;
+        blv_face.FromODM(face);
+        
+        RenderVertexSoft intersection;
+        if (Intersect_Ray_Face(pRay, pRay + 1, &fDepth, &intersection, &blv_face, i))
         {
-LABEL_8:
-          v10 = v8->uNumFaces;
-          v27 = v6;
-          v21 = v10;
-          if ( v10 > v6 )
-          {
-            v23 = v6;
-            do
-            {
-              v11 = (ODMFace *)((char *)v8->pFaces + v23);
-              if ( is_part_of_selection((BLVFace *)((char *)v8->pFaces + v23), filter) )
-              {
-                thisa.FromODM(v11);
-                if ( Intersect_Ray_Face(pRay, pRay + 1, &fDepth, &a1, &thisa, v26) )
-                {
-                  pGame->pIndoorCameraD3D->ViewTransform(&a1, 1u);
-                  v18 = v11;
-                  v13 = _48B561_mess_with_scaling_along_z(/*v12, */a1.vWorldViewPosition.x);
-                  LOWORD(v13) = 0;
-                  v20 = 2;
-                  v19 = (void *)((8 * (v27 | (v26 << 6)) | 6) + v13);
-                  pNumPointers = &list->uNumPointers;
-                  v15 = &list->object_pool[list->uNumPointers];
-                  v15->object = v18;
-                  v15 = (Vis_ObjectInfo *)((char *)v15 + 4);
-                  v15->object = v19;
-                  v15->sZValue = v20;
-                  ++*pNumPointers;
-                }
-              }
-              ++v27;
-              v23 += 308;
-            }
-            while ( v27 < v21 );
-            v6 = 0;
-          }
-          goto LABEL_15;
+          pGame->pIndoorCameraD3D->ViewTransform(&intersection, 1u);
+          int v13 = _48B561_mess_with_scaling_along_z(/*v12, */intersection.vWorldViewPosition.x);
+          LOWORD(v13) = (8 * (j | (i << 6)) | OBJECT_BModel) + v13;
+
+          list->AddObject(face, VisObjectType_Face, v13);
         }
       }
-      else
-      {
-        if ( v9 )
-          goto LABEL_8;
-      }
-LABEL_15:
-      v25 += 188;
-      v7 = v26++ + 1;
     }
-    while ( (signed int)v26 < (signed int)pOutdoor->uNumBModels );
   }
 }
 
@@ -509,7 +447,7 @@
   Vis_static_sub_4C1944_stru_F8BDE8.uNumPointers = 0;
   v6 = (double)a3;
   v8.object_type = VisObjectType_Sprite;
-  PickBillboards_All(v6, &Vis_static_sub_4C1944_stru_F8BDE8, &v8);
+  PickBillboards_Keyboard(v6, &Vis_static_sub_4C1944_stru_F8BDE8, &v8);
   Vis_static_sub_4C1944_stru_F8BDE8.create_object_pointers(Vis_SelectionList::Unique);
   sort_object_pointers(
     Vis_static_sub_4C1944_stru_F8BDE8.object_pointers,
@@ -1161,6 +1099,7 @@
           object_pointers[i] = &object_pool[i];
       }
     }
+    break;
 
     default:
       MessageBoxW(nullptr, L"Unknown pointer creation flag passed to ::create_object_pointers()", L"E:\\WORK\\MSDEV\\MM7\\MM7\\Code\\Vis.cpp:1358", 0);
@@ -1350,7 +1289,7 @@
 }
 
 //----- (004C288E) --------------------------------------------------------
-bool Vis::sort_objects_2(RenderVertexSoft *pArray, int sLeft, int sRight)
+bool Vis::SortByScreenSpaceX(RenderVertexSoft *pArray, int sLeft, int sRight)
 {
   bool result; // eax@1
   RenderVertexSoft *v5; // edx@2
@@ -1365,11 +1304,11 @@
   //float v13; // [sp+4Ch] [bp-24h]@4
   int v14; // [sp+64h] [bp-Ch]@7
   //Vis *thisa; // [sp+68h] [bp-8h]@1
-  void *thisa;
+  //void *thisa;
   //RenderVertexSoft *v16; // [sp+6Ch] [bp-4h]@2
   const void *v16;
 
-  thisa = this;
+  //thisa = this;
   if (sRight <= sLeft)
     return true;
   v5 = pArray;
@@ -1404,13 +1343,13 @@
   memcpy(&v11, &v5[v6], sizeof(v11));
   memcpy(&v5[v6], v16, sizeof(v5[v6]));
   memcpy((void *)v16, &v11, sizeof(0x30u));
-  sort_objects_2(v5, sLeft, v6 - 1);
-  sort_objects_2(pArray, v6 + 1, sRight);
+  SortByScreenSpaceX(v5, sLeft, v6 - 1);
+  SortByScreenSpaceX(pArray, v6 + 1, sRight);
   return true;
 }
 
 //----- (004C297E) --------------------------------------------------------
-bool Vis::sort_objects_3(RenderVertexSoft *pArray, int sLeft, int sRight)
+bool Vis::SortByScreenSpaceY(RenderVertexSoft *pArray, int sLeft, int sRight)
 {
   //bool result; // eax@1
   RenderVertexSoft *v5; // edx@2
@@ -1462,8 +1401,8 @@
   memcpy(&v11, &v5[v6], sizeof(0x30));
   memcpy(&v5[v6], v16, sizeof(v5[v6]));
   memcpy((void *)v16, &v11, sizeof(0x30));
-  sort_objects_3(v5, sLeft, v6 - 1);
-  sort_objects_3(pArray, v6 + 1, sRight);
+  SortByScreenSpaceY(v5, sLeft, v6 - 1);
+  SortByScreenSpaceY(pArray, v6 + 1, sRight);
   return true;
 }
 
@@ -1471,12 +1410,9 @@
 //----- (004C04AF) --------------------------------------------------------
 Vis::Vis()
 {
-  Vis *v1; // ebx@1
-  Vis *result; // eax@1
   RenderVertexSoft v3; // [sp+Ch] [bp-60h]@1
   RenderVertexSoft v4; // [sp+3Ch] [bp-30h]@1
 
-  v1 = this;
   v3.flt_2C = 0.0;
   v3.vWorldPosition.x = 0.0;
   v3.vWorldPosition.y = 65536.0;
@@ -1485,20 +1421,22 @@
   v4.vWorldPosition.x = 65536.0;
   v4.vWorldPosition.y = 0.0;
   v4.vWorldPosition.z = 0.0;
-  memcpy(&v1->stru_200C, &v4, sizeof(v1->stru_200C));
+  memcpy(&stru_200C, &v4, sizeof(stru_200C));
+
   v4.flt_2C = 0.0;
   v4.vWorldPosition.x = 0.0;
   v4.vWorldPosition.y = 65536.0;
   v4.vWorldPosition.z = 0.0;
-  memcpy(&v1->stru_203C, &v3, sizeof(v1->stru_203C));
+  memcpy(&stru_203C, &v3, sizeof(stru_203C));
+
   v3.flt_2C = 0.0;
   v3.vWorldPosition.x = 65536.0;
   v3.vWorldPosition.y = 0.0;
   v3.vWorldPosition.z = 0.0;
-  memcpy(&v1->stru_206C, &v3, sizeof(v1->stru_206C));
-  result = v1;
-  memcpy(&v1->stru_209C, &v4, sizeof(v1->stru_209C));
-  v1->field_20CC = 512;
+  memcpy(&stru_206C, &v3, sizeof(stru_206C));
+  memcpy(&stru_209C, &v4, sizeof(stru_209C));
+
+  keyboard_pick_depth = 512;
 }
 
 //----- (004C055C) --------------------------------------------------------
@@ -1520,11 +1458,11 @@
     list = &default_list;
   list->uNumPointers = 0;
 
-  PickBillboards_All(field_20CC, list, face_filter);
+  PickBillboards_Keyboard(keyboard_pick_depth, list, sprite_filter);
   if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
-    _4C0D32_KeyboardPickFaces_BLV(field_20CC, list, face_filter);
+    PickIndoorFaces_Keyboard(keyboard_pick_depth, list, face_filter);
   else if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
-    _4C0DEA_KeyboardPickFaces_ODM(field_20CC, list, face_filter);
+    PickOutdoorFaces_Keyboard(keyboard_pick_depth, list, face_filter);
   else
     assert(false);
 
@@ -1543,9 +1481,9 @@
   CastPickRay(pMouseRay, fMouseX, fMouseY, fDepth);
   PickBillboards_Mouse(fDepth, fMouseX, fMouseY, &default_list, sprite_filter);
   if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
-    PickIndoor(fDepth, pMouseRay, &default_list, face_filter);
+    PickIndoorFaces_Mouse(fDepth, pMouseRay, &default_list, face_filter);
   else
-    PickOutdoor(fDepth, pMouseRay, &default_list, face_filter, 0);
+    PickOutdoorFaces_Mouse(fDepth, pMouseRay, &default_list, face_filter, false);
   default_list.create_object_pointers(Vis_SelectionList::All);
   sort_object_pointers(default_list.object_pointers, 0, default_list.uNumPointers - 1);
 
@@ -1553,7 +1491,7 @@
 }
 
 //----- (004C06F8) --------------------------------------------------------
-void Vis::PickBillboards_All(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter)
+void Vis::PickBillboards_Keyboard(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter)
 {
   for (int i = 0; i < pRenderer->uNumBillboardsToDraw; ++i)
   {
@@ -1735,9 +1673,9 @@
     GetPolygonCenter(pRenderer->pBillboardRenderListD3D[v3].pQuards, 4, (float *)&v35, (float *)&v36);
     CastPickRay(pPickingRay, *(float *)&v35, *(float *)&v36, fDepth);
     if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
-      PickIndoor(fDepth, pPickingRay, &Vis_static_stru_F91E10, &vis_face_filter);
+      PickIndoorFaces_Mouse(fDepth, pPickingRay, &Vis_static_stru_F91E10, &vis_face_filter);
     else
-      PickOutdoor(fDepth, pPickingRay, &Vis_static_stru_F91E10, &vis_face_filter, 0);
+      PickOutdoorFaces_Mouse(fDepth, pPickingRay, &Vis_static_stru_F91E10, &vis_face_filter, false);
     Vis_static_stru_F91E10.create_object_pointers();
     sort_object_pointers(Vis_static_stru_F91E10.object_pointers, 0, Vis_static_stru_F91E10.uNumPointers - 1);
     if (Vis_static_stru_F91E10.uNumPointers)
@@ -1771,9 +1709,9 @@
                 v15 = v12;
                 CastPickRay(local_80, SLODWORD(v15), v14, fDepth);
                 if ( uCurrentlyLoadedLevelType == 1 )
-                  PickIndoor(fDepth, local_80, &Vis_static_stru_F91E10, &vis_face_filter);
+                  PickIndoorFaces_Mouse(fDepth, local_80, &Vis_static_stru_F91E10, &vis_face_filter);
                 else
-                  PickOutdoor(fDepth, local_80, &Vis_static_stru_F91E10, &vis_face_filter, 0);
+                  PickOutdoorFaces_Mouse(fDepth, local_80, &Vis_static_stru_F91E10, &vis_face_filter, false);
                 Vis_static_stru_F91E10.create_object_pointers();
                 sort_object_pointers(Vis_static_stru_F91E10.object_pointers, 0, Vis_static_stru_F91E10.uNumPointers - 1);
                 if ( !Vis_static_stru_F91E10.uNumPointers )
@@ -1818,8 +1756,8 @@
             || (double)pViewport->uScreenY > v41
             || (double)pViewport->uScreenW < v41
             || ((v25 = v23, CastPickRay(local_80, SLODWORD(v25), v41, fDepth), uCurrentlyLoadedLevelType != 1) ? 
-             (PickOutdoor(fDepth, local_80, &Vis_static_stru_F91E10, &vis_face_filter, 0)) : 
-             (PickIndoor(fDepth, local_80, &Vis_static_stru_F91E10, &vis_face_filter)),
+             (PickOutdoorFaces_Mouse(fDepth, local_80, &Vis_static_stru_F91E10, &vis_face_filter, false)) : 
+             (PickIndoorFaces_Mouse(fDepth, local_80, &Vis_static_stru_F91E10, &vis_face_filter)),
              (Vis_static_stru_F91E10.create_object_pointers(),
               sort_object_pointers(Vis_static_stru_F91E10.object_pointers, 0, Vis_static_stru_F91E10.uNumPointers - 1),
               Vis_static_stru_F91E10.uNumPointers)
@@ -1836,7 +1774,7 @@
 // F93E18: using guessed type char static_byte_F93E18_init;
 
 //----- (004C0D32) --------------------------------------------------------
-int Vis::_4C0D32_KeyboardPickFaces_BLV(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter)
+void Vis::PickIndoorFaces_Keyboard(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter)
 {
   int result; // eax@1
   signed int v5; // esi@2
@@ -1874,88 +1812,33 @@
     }
     result = i + 1;
   }
-  return result;
 }
 
 //----- (004C0DEA) --------------------------------------------------------
-void Vis::_4C0DEA_KeyboardPickFaces_ODM(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter)
+void Vis::PickOutdoorFaces_Keyboard(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter)
 {
-  int v4; // esi@1
-  BSPModel *v5; // ebx@3
-  unsigned __int8 v6; // zf@5
-  char v7; // sf@5
-  unsigned __int8 v8; // of@5
-  ODMFace *v9; // esi@7
-  unsigned int v10; // eax@8
-  Vis_ObjectInfo *v11; // eax@8
-  //unsigned int v12; // ecx@9
-  BLVFace f; // [sp+10h] [bp-84h]@1
-  //void *v14; // [sp+70h] [bp-24h]@9
-  //int v15; // [sp+74h] [bp-20h]@9
-  //unsigned int v16; // [sp+78h] [bp-1Ch]@9
-  int v17; // [sp+7Ch] [bp-18h]@1
-  Vis *v18; // [sp+80h] [bp-14h]@1
-  int v19; // [sp+84h] [bp-10h]@6
-  unsigned int v20; // [sp+88h] [bp-Ch]@2
-  int v21; // [sp+8Ch] [bp-8h]@5
-  int a1; // [sp+90h] [bp-4h]@1
+  for (uint i = 0; i < pOutdoor->uNumBModels; ++i)
+  {
+    int v17;
+    if (!IsBModelVisible(i, &v17))
+      continue;
+    if (!v17)
+      continue;
 
-  auto ecx0 = this;
-  v18 = ecx0;
-  v4 = 0;
-  v17 = 0;
-  a1 = 0;
-  if ( (signed int)pOutdoor->uNumBModels > 0 )
-  {
-    v20 = 0;
-    do
+    auto bmodel = pOutdoor->pBModels + i;
+    for (uint j = 0; j < bmodel->uNumFaces; ++j)
     {
-      v5 = &pOutdoor->pBModels[v20 / 0xBC];
-      if ( IsBModelVisible(a1, &v17) )
+      auto face = bmodel->pFaces + j;
+
+      if (is_part_of_selection(face, filter) )
       {
-        if ( v17 != v4 )
-        {
-          v8 = __OFSUB__(v5->uNumFaces, v4);
-          v6 = v5->uNumFaces == v4;
-          v7 = ((v5->uNumFaces - v4) & 0x80000000u) != 0;
-          v21 = v4;
-          if ( !((unsigned __int8)(v7 ^ v8) | v6) )
-          {
-            v19 = v4;
-            do
-            {
-              v9 = (ODMFace *)((char *)v5->pFaces + v19);
-              if ( is_part_of_selection((BLVFace *)((char *)v5->pFaces + v19), filter) )
-              {
-                f.FromODM(v9);
-                v10 = 8 * (v21 | (a1 << 6));
-                LOBYTE(v10) = v10 | OBJECT_BModel;
-                v11 = _4C1026(&f, v10, pick_depth);
-                if ( v11 )
-                {
-                  /*v14 = v11->object;
-                  v15 = v11->sZValue;
-                  v12 = a3->uNumPointers;
-                  //v16 = v11->uObjectType;
-                  v12 *= 3;
-                  *((int *)&a3->object_pool[0].object + v12) = (int)v14;
-                  *(&a3->object_pool[0].sZValue + v12) = v15;
-                  *(&a3->object_pool[0].object_type + v12) = v11->object_type;
-                  ++a3->uNumPointers;*/
-                  list->AddObject(v11->object, v11->object_type, v11->sZValue);
-                }
-              }
-              ++v21;
-              v19 += 308;
-            }
-            while ( v21 < (signed int)v5->uNumFaces );
-            v4 = 0;
-          }
-        }
+        BLVFace blv_face;
+        blv_face.FromODM(face);
+
+        int pid = 8 * (j | (i << 6)) | OBJECT_BModel;
+        if (auto object_info = _4C1026(&blv_face, pid, pick_depth))
+          list->AddObject(object_info->object, object_info->object_type, object_info->sZValue);
       }
-      ++a1;
-      v20 += 188;
     }
-    while ( a1 < (signed int)pOutdoor->uNumBModels );
   }
 }
\ No newline at end of file
--- a/Vis.h	Sat Feb 16 18:34:31 2013 +0200
+++ b/Vis.h	Sat Feb 16 20:24:02 2013 +0200
@@ -89,20 +89,22 @@
   //----- (004C05BE) --------------------------------------------------------
   ~Vis() {}
   bool PickKeyboard(Vis_SelectionList *list, Vis_SelectionFilter *sprite_filter, Vis_SelectionFilter *face_filter);
+  void PickBillboards_Keyboard(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter);
+  void PickIndoorFaces_Keyboard(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter);
+  void PickOutdoorFaces_Keyboard(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter);
+
   bool PickMouse(float fDepth, float fMouseX, float fMouseY, Vis_SelectionFilter *sprite_filter, Vis_SelectionFilter *face_filter);
   void PickBillboards_Mouse(float fPickDepth, float fX, float fY, Vis_SelectionList *list, Vis_SelectionFilter *filter);
-  void PickBillboards_All(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter);
+  void PickIndoorFaces_Mouse(float fDepth, struct RenderVertexSoft *pRay, Vis_SelectionList *list, Vis_SelectionFilter *filter);
+  void PickOutdoorFaces_Mouse(float fDepth, struct RenderVertexSoft *pRay, Vis_SelectionList *list, Vis_SelectionFilter *filter, bool one_sided);
+
   bool is_part_of_selection(void *uD3DBillboardIdx_or_pBLVFace_or_pODMFace, Vis_SelectionFilter *filter);
   bool DoesRayIntersectBillboard(float fDepth, unsigned int uD3DBillboardIdx);
-  int _4C0D32_KeyboardPickFaces_BLV(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter);
-  void _4C0DEA_KeyboardPickFaces_ODM(float pick_depth, Vis_SelectionList *list, Vis_SelectionFilter *filter);
-  Vis_ObjectInfo *_4C1026(struct BLVFace *a2, unsigned int a3, float a4);
-  char _4C12C3_FindSomeBillboard(struct RenderVertexSoft *a1, int a2, float a3, float a4);
+  Vis_ObjectInfo *_4C1026(struct BLVFace *face, unsigned int a3, float pick_depth);
+  bool IsPolygonOccludedByBillboard(struct RenderVertexSoft *vertices, int num_vertices, float x, float y);
   void GetPolygonCenter(struct RenderVertexD3D3 *pVertices, unsigned int uNumVertices, float *pCenterX, float *pCenterY);
-  float *_4C1495(struct RenderVertexSoft *Src, int a2, float *a3, float *a4);
+  void GetPolygonScreenSpaceCenter(struct RenderVertexSoft *vertices, int num_vertices, float *out_center_x, float *out_center_y);
   bool IsPointInsideD3DBillboard(struct RenderBillboardD3D *a1, float x, float y);
-  void PickIndoor(float fDepth, struct RenderVertexSoft *pRay, Vis_SelectionList *list, Vis_SelectionFilter *filter);
-  void PickOutdoor(float fDepth, struct RenderVertexSoft *pRay, Vis_SelectionList *list, Vis_SelectionFilter *filter, char a6);
   int _4C1944(int object_id, unsigned int a3, int a4, int a5, int a6);
   void _4C1A02();
   bool SortVectors_x(RenderVertexSoft *a2, int a3, int a4);
@@ -116,8 +118,8 @@
   void sort_object_pointers(Vis_ObjectInfo **pPointers, int left, int right);
   bool SortVerticesByX(struct RenderVertexD3D3 *a2, unsigned int uStart, unsigned int uEnd);
   bool SortVerticesByY(struct RenderVertexD3D3 *a2, unsigned int uStart, unsigned int uEnd);
-  bool sort_objects_2(struct RenderVertexSoft *pArray, int sLeft, int sRight);
-  bool sort_objects_3(struct RenderVertexSoft *pArray, int sLeft, int sRight);
+  bool SortByScreenSpaceX(struct RenderVertexSoft *pArray, int sLeft, int sRight);
+  bool SortByScreenSpaceY(struct RenderVertexSoft *pArray, int sLeft, int sRight);
 
   void (__thiscall ***vdestructor_ptr)(Vis *, bool);
   Vis_SelectionList default_list;
@@ -125,6 +127,6 @@
   RenderVertexSoft  stru_203C;
   RenderVertexSoft  stru_206C;
   RenderVertexSoft  stru_209C;
-  int field_20CC;
+  int keyboard_pick_depth;
 };
 #pragma pack(pop)
--- a/mm7_2.cpp	Sat Feb 16 18:34:31 2013 +0200
+++ b/mm7_2.cpp	Sat Feb 16 20:24:02 2013 +0200
@@ -15205,7 +15205,7 @@
 }
 
 //----- (0046A14B) --------------------------------------------------------
-char __cdecl OnPressSpace()
+void OnPressSpace()
 {
   //SHORT v0; // ax@2
   int *v1; // eax@2
@@ -15235,8 +15235,7 @@
     pGame->PickKeyboard(GetAsyncKeyState(VK_CONTROL) & 0x8001, &vis_sprite_filter_3, &vis_door_filter);
     v1 = (int *)pGame->pVisInstance->get_picked_object_zbuf_val();
     if ( v1 != (int *)-1 )
-      LOBYTE(v1) = DoInteractionWithTopmostZObject((unsigned __int16)v1, (signed int)(unsigned __int16)v1 >> 3);
-    return (char)v1;
+      DoInteractionWithTopmostZObject((unsigned __int16)v1, (signed int)(unsigned __int16)v1 >> 3);
   }
   v22 = 0;
   v1 = (int *)((signed int)(viewparams->uScreenZ + viewparams->uScreenX) >> 1);
@@ -15333,10 +15332,7 @@
     if ( !(char)v1 )
       break;
   }
-  return (char)v1;
-}
-// 72065C: using guessed type int dword_72065C[];
-// 7207EC: using guessed type int dword_7207EC[];
+}
 
 //----- (0046A334) --------------------------------------------------------
 char __fastcall DoInteractionWithTopmostZObject(int a1, int a2)
--- a/mm7_data.h	Sat Feb 16 18:34:31 2013 +0200
+++ b/mm7_data.h	Sat Feb 16 20:24:02 2013 +0200
@@ -2145,7 +2145,7 @@
 void __cdecl OnPaperdollLeftClick();
 int __thiscall UnprojectX(int x);
 int __thiscall UnprojectY(int _this);
-char __cdecl OnPressSpace();
+void OnPressSpace();
 char __fastcall DoInteractionWithTopmostZObject(int a1, int a2);
 int __fastcall sub_46A6AC(int a1, int a2, int a3);
 int __fastcall sub_46A7C8(int a1, int a2, signed int a3);