ItemSorter.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2003-2004 The Pentagram team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00019 #include "pent_include.h"
00020 #include "ItemSorter.h"
00021 
00022 #include "Item.h"
00023 #include "Shape.h"
00024 #include "ShapeFrame.h"
00025 #include "ShapeInfo.h"
00026 #include "MainShapeArchive.h"
00027 #include "RenderSurface.h"
00028 #include "Rect.h"
00029 #include "GameData.h"
00030 
00031 // temp
00032 #include "WeaponOverlay.h"
00033 #include "MainActor.h"
00034 #include "getObject.h"
00035 // --
00036 
00037 using Pentagram::Rect;
00038 
00039 #if 0
00040 template<class _T> class MyVector
00041 {
00042 public:
00043         typedef _T *iterator;
00044         typedef _T &reference;
00045 
00046 private:
00047         iterator        _begin;
00048         iterator        _end;
00049         iterator        _last;
00050 
00051 public:
00052         MyVector() 
00053         {
00054                 _begin = 0;
00055                 _end = 0;
00056                 _last = 0;
00057         }
00058 
00059         iterator push_back(reference _R)
00060         {
00061                 if (!_begin)
00062                 {
00063                         _begin = new _T[1];
00064                         _end = _last = _begin + 1;
00065                         *_begin = _R;
00066                         return _begin;
00067                 }
00068                 
00069                 if (_end == _last)      // At the end of the list, need to allocate more
00070                 {
00071                         size_t _capacity = _last - _begin;
00072                         iterator _new = new _T[_capacity*2];
00073                         std::memcpy (_new, _begin, _capacity * sizeof(_T));
00074                         _end = _new + (_end - _begin);
00075                         delete [] _begin;
00076                         _begin = _new;
00077                         _last = _begin + (_capacity*2);
00078                 }
00079                 *_end = _R;
00080                 _end++;
00081                 return _end-1;
00082         }
00083 
00084         void clear() { _end = _begin; }
00085 
00086         iterator begin() { return _begin; }
00087         iterator end() { return _end; }
00088 private:
00089 
00090         
00091 };
00092 
00093 #endif
00094 
00095 // This does NOT need to be in the header
00096 
00097 struct SortItem
00098 {
00099         SortItem() : item_num(0), shape(0), order(-1), depends() { }
00100 
00101         uint16                                  item_num;       // Owner item number
00102 
00103         Shape                                   *shape;
00104         uint32                                  shape_num;
00105         uint32                                  frame;
00106         uint32                                  flags;          // Item flags
00107         uint32                                  ext_flags;      // Item extended flags
00108 
00109         int                                             sx, sx2;        // Screenspace X coords
00110         int                                             sy, sy2;        // Screenspace Y coords
00111 
00112         /*
00113                                 Bounding Box layout
00114 
00115                    1    
00116                  /   \      
00117            /       \     1 = Left  Far  Top LFT --+
00118          2           3   2 = Left  Near Top LNT -++
00119          | \       / |   3 = Right Far  Top RFT +-+
00120          |   \   /   |   4 = Right Near Top RNT +++
00121          |     4     |   5 = Left  Near Bot LNB -+-
00122          |     |     |   6 = Right Far  Bot RFB +--
00123          5     |     6   7 = Right Near Bot LNB ++- 
00124            \   |   /     8 = Left  Far  Bot LFB --- (not shown)
00125                  \ | /    
00126                    7    
00127 
00128         */
00129 
00130         sint32  x, xleft;       // Worldspace bounding box x (xright = x)
00131         sint32  y, yfar;        // Worldspace bounding box y (ynear = y)
00132         sint32  z, ztop;        // Worldspace bounding box z (ztop = z)
00133 
00134         sint32  sxleft;         // Screenspace bounding box left extent    (LNT x coord)
00135         sint32  sxright;        // Screenspace bounding box right extent   (RFT x coord)
00136 
00137         sint32  sxtop;          // Screenspace bounding box top x coord    (LFT x coord)
00138         sint32  sytop;          // Screenspace bounding box top extent     (LFT y coord)
00139 
00140         sint32  sxbot;          // Screenspace bounding box bottom x coord (RNB x coord) ss origin
00141         sint32  sybot;          // Screenspace bounding box bottom extent  (RNB y coord) ss origin
00142 
00143         bool    f32x32 : 1;                     // Needs 1 bit  0
00144         bool    flat : 1;                       // Needs 1 bit  1
00145         bool    occl : 1;                       // Needs 1 bit  2
00146         bool    solid : 1;                      // Needs 1 bit  3
00147         bool    draw : 1;                       // Needs 1 bit  4
00148         bool    roof : 1;                       // Needs 1 bit  5
00149         bool    noisy : 1;                      // Needs 1 bit  6
00150         bool    anim : 1;                       // Needs 1 bit  7
00151         bool    trans : 1;                      // Needs 1 bit  8
00152         bool    fixed : 1;
00153         bool    land : 1;
00154 
00155         bool    occluded : 1;           // Set true if occluded
00156 
00157         sint16  clipped;                        // Clipped to RenderSurface
00158 
00159         sint32  order;          // Rendering order. -1 is not yet drawn
00160 
00161         std::vector<SortItem *> depends;        // All this Items dependencies (i.e. all objects behind)
00162 //      MyVector<SortItem *>    depends;        // All this Items dependencies (i.e. all objects behind)
00163 
00164         // Functions
00165 
00166         // Check to see if we overlap si2
00167         inline bool overlap(const SortItem &si2) const;
00168 
00169         // Check to see if we occlude si2
00170         inline bool occludes(const SortItem &si2) const;
00171 
00172         // Operator less than
00173         inline bool operator<(const SortItem& si2) const;
00174 
00175         // Operator left shift (ok, what this does it output the comparisons)
00176         inline bool operator<<(const SortItem& si2) const;
00177 
00178 };
00179 
00180 typedef std::vector<SortItem *> SortItemVector;
00181 //typedef MyVector<SortItem *> SortItemVector;
00182 
00183 // Check to see if we overlap si2
00184 inline bool SortItem::overlap(const SortItem &si2) const
00185 {
00186         const int point_top_diff[2] = { sxtop - si2.sxbot, sytop - si2.sybot };
00187         const int point_bot_diff[2] = { sxbot - si2.sxtop, sybot - si2.sytop };
00188 
00189         // This function is a bit of a hack. It uses dot products between
00190         // points and the lines. Nothing is normalized since that isn't 
00191         // important
00192 
00193         // 'normal' of top  left line ( 2,-1) of the bounding box
00194         const sint32 dot_top_left = point_top_diff[0] + point_top_diff[1] * 2;
00195 
00196         // 'normal' of top right line ( 2, 1) of the bounding box
00197         const sint32 dot_top_right = -point_top_diff[0] + point_top_diff[1] * 2;
00198 
00199         // 'normal' of bot  left line (-2,-1) of the bounding box
00200         const sint32 dot_bot_left =  point_bot_diff[0] - point_bot_diff[1] * 2;
00201 
00202         // 'normal' of bot right line (-2, 1) of the bounding box
00203         const sint32 dot_bot_right = -point_bot_diff[0] - point_bot_diff[1] * 2;
00204 
00205         const bool right_clear = sxright <= si2.sxleft;
00206         const bool left_clear = sxleft >= si2.sxright;
00207         const bool top_left_clear = dot_top_left >= 0;
00208         const bool top_right_clear = dot_top_right >= 0;
00209         const bool bot_left_clear = dot_bot_left >= 0;
00210         const bool bot_right_clear = dot_bot_right >= 0;
00211 
00212         const bool clear = right_clear | left_clear | 
00213                 bot_right_clear | bot_left_clear |
00214                 top_right_clear | top_left_clear;
00215 
00216         return !clear;
00217 }
00218 
00219 // Check to see if we occlude si2
00220 inline bool SortItem::occludes(const SortItem &si2) const
00221 {
00222         const int point_top_diff[2] = { sxtop - si2.sxtop, sytop - si2.sytop };
00223         const int point_bot_diff[2] = { sxbot - si2.sxbot, sybot - si2.sybot };
00224 
00225         // This function is a bit of a hack. It uses dot products between
00226         // points and the lines. Nothing is normalized since that isn't 
00227         // important
00228 
00229         // 'normal' of top left line ( 2, -1) of the bounding box
00230         const sint32 dot_top_left = point_top_diff[0] + point_top_diff[1] * 2;
00231 
00232         // 'normal' of top right line ( 2, 1) of the bounding box
00233         const sint32 dot_top_right = -point_top_diff[0] + point_top_diff[1] * 2;
00234 
00235         // 'normal' of bot  left line (-2,-1) of the bounding box
00236         const sint32 dot_bot_left =  point_bot_diff[0] - point_bot_diff[1] * 2;
00237 
00238         // 'normal' of bot right line (-2, 1) of the bounding box
00239         const sint32 dot_bot_right = -point_bot_diff[0] - point_bot_diff[1] * 2;
00240 
00241 
00242         const bool right_res = sxright >= si2.sxright;
00243         const bool left_res = sxleft <= si2.sxleft;
00244         const bool top_left_res = dot_top_left <= 0;
00245         const bool top_right_res = dot_top_right <= 0;
00246         const bool bot_left_res = dot_bot_left <= 0;
00247         const bool bot_right_res = dot_bot_right <= 0;
00248 
00249         const bool occluded = right_res & left_res & 
00250                 bot_right_res & bot_left_res &
00251                 top_right_res & top_left_res;
00252 
00253         return occluded;
00254 }
00255 
00256 inline bool SortItem::operator<(const SortItem& si2) const
00257 {
00258         const SortItem& si1 = *this;
00259         
00260         // Specialist z flat handling
00261         if (si1.flat && si2.flat)
00262         {
00263                 // Differing z is easy for flats
00264                 if (si1.ztop != si2.ztop) return si1.ztop < si2.ztop;
00265 
00266                 // Equal z
00267 
00268                 // Animated always gets drawn after
00269                 if (si1.anim != si2.anim) return si1.anim < si2.anim;
00270 
00271                 // Trans always gets drawn after
00272                 if (si1.trans != si2.trans) return si1.trans < si2.trans;
00273 
00274                 // Draw always gets drawn first
00275                 if (si1.draw != si2.draw) return si1.draw > si2.draw;
00276 
00277                 // Solid always gets drawn first
00278                 if (si1.solid != si2.solid) return si1.solid > si2.solid;
00279 
00280                 // Occludes always get drawn first
00281                 if (si1.occl != si2.occl) return si1.occl > si2.occl;
00282 
00283                 // 32x32 flats get drawn first
00284                 if (si1.f32x32 != si2.f32x32) return si1.f32x32 > si2.f32x32;
00285         }
00286         // Mixed, or non flat
00287         else {
00288 
00289                 // Clearly X, Y and Z (useful?)
00290                 //if (si1.x <= si2.xleft && si1.y <= si2.yfar && si1.ztop <= si2.z) return true;
00291                 //else if (si1.xleft >= si2.x && si1.yfar >= si2.y && si1.z >= si2.ztop) return false;
00292 
00293                 //int front1 = si1.x + si1.y;
00294                 //int rear1 = si1.xleft + si1.yfar;
00295                 //int front2 = si2.x + si2.y;
00296                 //int rear2 = si2.xleft + si2.yfar;
00297 
00298                 // Rear of object is infront of other's front
00299                 //if (front1 <= rear2) return true;
00300                 //else if (rear1 >= front2) return false;
00301 
00302                 // Clearly in z
00303                 if (si1.ztop <= si2.z) return true;
00304                 else if (si1.z >= si2.ztop) return false;
00305 
00306                 // Partial in z
00307                 //if (si1.ztop != si2.ztop) return si1.ztop < si2.ztop;
00308         }
00309 
00310         // Clearly in x and y? (useful?)
00311         //if (si1.x <= si2.xleft && si1.y <= si2.yfar) return true;
00312         //else if (si1.xleft >= si2.x && si1.yfar >= si2.y) return false;
00313 
00314         // Clearly in x?
00315         if (si1.x <= si2.xleft) return true;
00316         else if (si1.xleft >= si2.x) return false;
00317 
00318         // Clearly in y?
00319         if (si1.y <= si2.yfar) return true;
00320         else if (si1.yfar >= si2.y) return false;
00321 
00322         // Are overlapping in all 3 dimentions if we come here
00323 
00324         // ZTops?
00325         if (si1.ztop < si2.ztop) return true;
00326         else if (si1.ztop > si2.ztop) return false;
00327 
00328         // Biased Clearly in z
00329         if ((si1.ztop+si1.z)/2 <= si2.z) return true;
00330         else if (si1.z >= (si2.ztop+si2.z)/2) return false;
00331 
00332         // Biased Clearly X
00333         if ((si1.x+si1.xleft)/2 <= si2.xleft) return true;
00334         else if (si1.xleft >= (si2.x+si2.xleft)/2) return false;
00335 
00336         // Biased Clearly Y
00337         if ((si1.y+si1.yfar)/2 <= si2.yfar) return true;
00338         else if (si1.yfar >= (si2.y+si2.yfar)/2) return false;
00339 
00340         // Partial in X + Y front
00341         if (si1.x + si1.y != si1.x + si2.y) return (si1.x + si1.y < si2.x + si2.y);
00342 
00343         // Partial in X + Y back
00344         if (si1.xleft + si1.yfar != si1.xleft + si2.yfar) return (si1.xleft + si1.yfar < si2.xleft + si2.yfar);
00345 
00346         // Partial in x?
00347         if (si1.x != si2.x) return si1.x < si2.x;
00348 
00349         // Partial in y?
00350         if (si1.y != si2.y) return si1.y < si2.y;
00351 
00352         // Just sort by shape number - not a number any more (is a pointer)
00353         if (si1.shape_num != si2.shape_num) return si1.shape_num < si2.shape_num;
00354 
00355         // And then by frame
00356         return si1.frame < si2.frame;
00357 }
00358 
00359 #define COMPARISON_RETURN(val,op,tab)                                                           \
00360                 pout << tab"if (si1."#val" != si2."#val") -> ("                         \
00361                                 << si1.val << " != " << si2.val << ") -> "                      \
00362                                 << (si1.val != si2.val) << std::endl;                           \
00363                 pout << tab"{" << std::endl;                                                            \
00364                 if (si1.val != si2.val)                                                                         \
00365                 {                                                                                                                       \
00366                         pout << tab"\treturn si1."#val" "#op" si2."#val"; -> (" \
00367                                                 << si1.val << " "#op" " << si2.val << ") -> "\
00368                                                 << (si1.val op si2.val) << std::endl;           \
00369                         return si1.val op si2.val;                                                              \
00370                 }                                                                                                                       \
00371                 pout << tab"}" << std::endl;
00372 
00373 #define COMPARISON_RETURN_EX(val1,op,val2,tab)                                          \
00374                 pout << tab"if ("#val1" != "#val2") -> ("                                       \
00375                                 << val1 << " != " << val2 << ") -> "                            \
00376                                 << (val1 != val2) << std::endl;                                         \
00377                 pout << tab"{" << std::endl;                                                            \
00378                 if (val1 != val2)                                                                                       \
00379                 {                                                                                                                       \
00380                         pout << tab"\treturn "#val1" "#op" "#val2"; -> ("               \
00381                                                 << val1 << " "#op" " << val2 << ") -> "         \
00382                                                 << (val1 op val2) << std::endl;                         \
00383                         return val1 op val2;                                                                    \
00384                 }                                                                                                                       \
00385                 pout << tab"}" << std::endl;
00386 
00387 #define COMPARISON_RETURN_TF(val1,op,val2,tf,tab)                                       \
00388         pout << tab "if ("#val1" "#op" "#val2") -> ("                                   \
00389                                 << val1 << " "#op" " << val2 << ") -> "                         \
00390                                 << (val1 op val2) << std::endl;                                         \
00391                 pout << tab"{" << std::endl;                                                            \
00392                 if (val1 op val2)                                                                                       \
00393                 {                                                                                                                       \
00394                         pout << tab"\treturn " << tf << std::endl;                              \
00395                         return tf;                                                                                              \
00396                 }                                                                                                                       \
00397                 pout << tab"}" << std::endl;
00398 
00399 inline bool SortItem::operator<<(const SortItem& si2) const
00400 {
00401         const SortItem& si1 = *this;
00402         
00403         if (si2.overlap(si1)) pout << "Overlaping" << std::endl;
00404         else 
00405         {
00406                  pout << "Not Overlaping" << std::endl;
00407                  return false;
00408         }
00409 
00410         // Specialist z flat handling
00411         pout << "if (si1.flat && si2.flat) -> if (" 
00412                         << si1.flat << " && " << si2.flat << ") -> " 
00413                         << (si1.flat && si2.flat) << std::endl;
00414         pout << "{" << std::endl;
00415 
00416         if (si1.flat && si2.flat)
00417         {
00418                 // Differing z is easy for flats
00419                 //if (si1.ztop != si2.ztop) return si1.ztop < si2.ztop;
00420                 COMPARISON_RETURN(ztop,<,"\t");
00421 
00422                 // Equal z
00423 
00424                 // Animated always gets drawn after
00425                 //if (si1.anim != si2.anim) return si1.anim < si2.anim;
00426                 COMPARISON_RETURN(anim,<,"\t");
00427 
00428                 // Trans always gets drawn after
00429                 //if (si1.trans != si2.trans) return si1.trans < si2.trans;
00430                 COMPARISON_RETURN(trans,<,"\t");
00431 
00432                 // Draw always gets drawn first
00433                 //if (si1.draw != si2.draw) return si1.draw > si2.draw;
00434                 COMPARISON_RETURN(draw,>,"\t");
00435 
00436                 // Solid always gets drawn first
00437                 //if (si1.solid != si2.solid) return si1.solid > si2.solid;
00438                 COMPARISON_RETURN(solid,>,"\t");
00439 
00440                 // Occludes always get drawn first
00441                 //if (si1.occl != si2.occl) return si1.occl > si2.occl;
00442                 COMPARISON_RETURN(occl,>,"\t");
00443 
00444                 // 32x32 flats get drawn first
00445                 //if (si1.f32x32 != si2.f32x32) return si1.f32x32 > si2.f32x32;
00446                 COMPARISON_RETURN(f32x32,>,"\t");
00447         }
00448         // Mixed, or non flat
00449         else {
00450                 pout << "}" << std::endl;
00451                 pout << "else" << std::endl;
00452                 pout << "{" << std::endl;
00453 
00454                 // Clearly X, Y and Z  (useful?)
00455                 //if (si1.x <= si2.xleft && si1.y <= si2.yfar && si1.ztop <= si2.z) return true;
00456                 //else if (si1.xleft >= si2.x && si1.yfar >= si2.y && si1.z >= si2.ztop) return false;
00457 
00458                 //int front1 = si1.x + si1.y;
00459                 //int rear1 = si1.xleft + si1.yfar;
00460                 //int front2 = si2.x + si2.y;
00461                 //int rear2 = si2.xleft + si2.yfar;
00462 
00463                 // Rear of object is infront of other's front
00464                 //if (front1 <= rear2) return true;
00465                 //else if (rear1 >= front2) return false;
00466                 //COMPARISON_RETURN_TF(front1,<=,rear2,true,"\t");
00467                 //COMPARISON_RETURN_TF(rear1,>=,front2,false,"\t");
00468 
00469                 // Clearly in z
00470                 //if (si1.ztop <= si2.z) return true;
00471                 //else if (si1.z >= si2.ztop) return false;
00472                 COMPARISON_RETURN_TF(si1.ztop,<=,si2.z,true,"\t");
00473                 COMPARISON_RETURN_TF(si1.z,>=,si2.ztop,false,"\t");
00474 
00475                 // Partial in z
00476                 //if (si1.ztop != si2.ztop) return si1.ztop < si2.ztop;
00477         }
00478         pout << "}" << std::endl;
00479 
00480         // Clearly in x and y? (useful?)
00481         //if (si1.x <= si2.xleft && si1.y <= si2.yfar) return true;
00482         //else if (si1.xleft >= si2.x && si1.yfar >= si2.y) return false;
00483 
00484         // Clearly X
00485         //if (si1.x <= si2.xleft) return true;
00486         //else if (si1.xleft >= si2.x) return false;
00487         COMPARISON_RETURN_TF(si1.x,<=,si2.xleft,true,"\t");
00488         COMPARISON_RETURN_TF(si1.xleft,>=,si2.x,false,"\t");
00489 
00490         // Clearly Y
00491         //if (si1.y <= si2.yfar) return true;
00492         //else if (si1.yfar >= si2.y) return false;
00493         COMPARISON_RETURN_TF(si1.y,<=,si2.yfar,true,"\t");
00494         COMPARISON_RETURN_TF(si1.yfar,>=,si2.y,false,"\t");
00495 
00496         // ZTops?
00497         COMPARISON_RETURN_TF(si1.ztop,<,si2.z,true,"");
00498         COMPARISON_RETURN_TF(si1.ztop,>,si2.ztop,false,"");
00499 
00500         // Biased Clearly in z
00501         //if ((si1.ztop+si1.z)/2 <= si2.z) return true;
00502         //else if (si1.z >= (si2.ztop+si2.z)/2) return false;
00503         COMPARISON_RETURN_TF((si1.ztop+si1.z)/2,<=,si2.z,true,"");
00504         COMPARISON_RETURN_TF(si1.z,>=,(si2.ztop+si2.z)/2,false,"");
00505 
00506         // Biased Clearly X
00507         //if ((si1.x+si1.xleft)/2 <= si2.xleft) return true;
00508         //else if (si1.xleft >= (si2.x+si2.xleft)/2) return false;
00509         COMPARISON_RETURN_TF((si1.x+si1.xleft)/2,<=,si2.xleft,true,"");
00510         COMPARISON_RETURN_TF(si1.xleft,>=,(si2.x+si2.xleft)/2,false,"");
00511 
00512         // Biased Clearly Y
00513         //if ((si1.y+si1.yfar)/2 <= si2.yfar) return true;
00514         //else if (si1.yfar >= (si2.y+si2.yfar)/2) return false;
00515         COMPARISON_RETURN_TF((si1.y+si1.yfar)/2,<=,si2.yfar,true,"");
00516         COMPARISON_RETURN_TF(si1.yfar,>=,(si2.y+si2.yfar)/2,false,"");
00517 
00518         // Partial in X + Y front
00519         //if (si1.x + si1.y != si1.x + si2.y) return (si1.x + si1.y < si2.x + si2.y);
00520         COMPARISON_RETURN_EX(si1.x + si1.y,<,si1.x + si2.y,"");
00521 
00522         // Partial in X + Y back
00523         //if (si1.xleft + si1.yfar != si1.xleft + si2.yfar) return (si1.xleft + si1.yfar < si2.xleft + si2.yfar);
00524         COMPARISON_RETURN_EX(si1.xleft + si1.yfar,<,si1.xleft + si2.yfar,"");
00525 
00526         // Partial in x?
00527         //if (si1.x != si2.x) return si1.x < si2.x;
00528         COMPARISON_RETURN(x,<,"");
00529 
00530         // Partial in y?
00531         //if (si1.y != si2.y) return si1.y < si2.y;
00532         COMPARISON_RETURN(y,<,"");
00533 
00534         // Just sort by shape number
00535 //      if (si1.shape_num != si2.shape_num) return si1.shape_num < si2.shape_num;
00536         COMPARISON_RETURN(shape_num,<,"");
00537 
00538         // And then by frame
00539         //return si1.frame < si2.frame;
00540         COMPARISON_RETURN(frame,<,"");
00541         return 0;
00542 }
00543 
00544 // 
00545 // ItemSorter
00546 //
00547 
00548 ItemSorter::ItemSorter(int Max_Items) : 
00549                 shapes(0), surf(0), max_items(Max_Items), num_items(0), num_extra(0), sort_limit(0)
00550 {
00551         if (max_items <= 0) max_items = Max_Items = 2048;
00552         items = new SortItem [max_items];
00553 }
00554 
00555 ItemSorter::~ItemSorter()
00556 {
00557         delete [] items;
00558 }
00559 
00560 void ItemSorter::BeginDisplayList(RenderSurface *rs,
00561                                                                   sint32 camx, sint32 camy, sint32 camz)
00562 {
00563         // Get the shapes, if required
00564         if (!shapes) shapes = GameData::get_instance()->getMainShapes();
00565 
00566         // Need to resize
00567         if (num_extra)
00568         {
00569                 delete [] items;
00570                 max_items += num_extra*2;
00571                 items = new SortItem [max_items];
00572         }
00573         // Set the RenderSurface, and reset the item list
00574         surf = rs;
00575         num_items = 0;
00576         order_counter = 0;
00577         num_extra = 0;
00578 
00579         // Screenspace bounding box bottom x coord (RNB x coord)
00580         cam_sx = (camx - camy)/4;
00581         // Screenspace bounding box bottom extent  (RNB y coord)
00582         cam_sy = (camx + camy)/8 - camz;
00583 }
00584 
00585 void ItemSorter::AddItem(sint32 x, sint32 y, sint32 z, uint32 shape_num, uint32 frame_num, uint32 flags, uint32 ext_flags, uint16 item_num)
00586 {
00587         //if (z > skip_lift) return;
00588         //if (Application::tgwds && shape == 538) return;
00589 
00590         // First thing, get a SortItem to use
00591         
00592         if (num_items >= max_items)
00593         {
00594                 num_extra++;
00595                 return;
00596         }
00597 
00598         SortItem *si = items+num_items;
00599 
00600         si->item_num = item_num;
00601         si->shape = shapes->getShape(shape_num);
00602         si->shape_num = shape_num;
00603         si->frame = frame_num;
00604         ShapeFrame *frame = si->shape->getFrame(si->frame);
00605         if (!frame) {
00606                 perr << "Invalid shape: " << si->shape_num << "," << si->frame
00607                          << std::endl;
00608                 return;
00609         }
00610 
00611         ShapeInfo *info = shapes->getShapeInfo(shape_num);
00612 
00613         //if (info->is_editor && !show_editor_items) return;
00614         //if (info->z > shape_max_height) return;
00615 
00616         // Dimensions
00617         sint32 xd, yd, zd;
00618         si->flags = flags;
00619         si->ext_flags = ext_flags;
00620 
00621         // X and Y are flipped
00622         if (si->flags & Item::FLG_FLIPPED) 
00623         {
00624                 xd = info->y * 32;      // Multiply by 32 to get actual world size
00625                 yd = info->x * 32;      // Multiply by 32 to get actual world size
00626         }
00627         else
00628         {
00629                 xd = info->x * 32;      // Multiply by 32 to get actual world size
00630                 yd = info->y * 32;      // Multiply by 32 to get actual world size
00631         }
00632 
00633         zd = info->z * 8;       // Multiply by 8 to get actual world size
00634 
00635         // Worldspace bounding box
00636         si->x = x; si->y = y; si->z = z;
00637         si->xleft = si->x - xd;
00638         si->yfar = si->y - yd;
00639         si->ztop = si->z + zd;
00640 
00641         // Screenspace bounding box left extent    (LNT x coord)
00642         si->sxleft = (si->xleft - si->y)/4 - cam_sx;
00643         // Screenspace bounding box right extent   (RFT x coord)
00644         si->sxright= (si->x - si->yfar)/4 - cam_sx;
00645 
00646         // Screenspace bounding box top x coord    (LFT x coord)
00647         si->sxtop = (si->xleft - si->yfar)/4 - cam_sx;
00648         // Screenspace bounding box top extent     (LFT y coord)
00649         si->sytop = (si->xleft + si->yfar)/8 - si->ztop - cam_sy;
00650 
00651         // Screenspace bounding box bottom x coord (RNB x coord)
00652         si->sxbot = (si->x - si->y)/4 - cam_sx;
00653         // Screenspace bounding box bottom extent  (RNB y coord)
00654         si->sybot = (si->x + si->y)/8 - si->z - cam_sy;
00655 
00656 //      si->sxleft += swo2;
00657 //      si->sxright += swo2;
00658 //      si->sxbot += swo2;
00659 //      si->sxtop += swo2;
00660 
00661 //      si->sytop += sho2;
00662 //      si->sybot += sho2;
00663 
00664         // Real Screenspace coords
00665         si->sx = si->sxbot - frame->xoff;       // Left
00666         si->sy = si->sybot - frame->yoff;       // Top
00667         si->sx2 = si->sx + frame->width;        // Right
00668         si->sy2 = si->sy + frame->height;       // Bottom
00669 
00670         // Do Clipping here
00671         si->clipped = surf->CheckClipped(Rect (si->sx,si->sy, frame->width, frame->height));
00672         if (si->clipped < 0) return;
00673 
00674         // These help out with sorting. We calc them now, so it will be faster
00675         si->f32x32 = xd==128 && yd==128;
00676         si->flat = zd == 0;
00677 
00678         /*
00679         if (Application::tgwds) {
00680                 si->draw = false;
00681                 si->solid = false;
00682                 si->occl = false;
00683                 si->roof = false;
00684                 si->noisy = false;
00685                 si->anim = false;
00686                 si->trans = false;
00687         }
00688         else
00689         */
00690         {
00691                 si->draw = info->is_draw();
00692                 si->solid = info->is_solid();
00693                 si->occl = info->is_occl() && !(si->ext_flags & Item::FLG_INVISIBLE);
00694                 si->roof = info->is_roof();
00695                 si->noisy = info->is_noisy();
00696                 si->anim = info->animtype != 0;
00697                 si->trans = info->is_translucent();
00698                 si->fixed = info->is_fixed();
00699                 si->land = info->is_land();
00700         }
00701 
00702         si->occluded = false;
00703         si->order = -1;
00704 
00705         // We will clear all the vector memory
00706         // Stictly speaking the vector will sort of leak memory, since they
00707         // are never deleted
00708         //si->depends.clear();
00709         si->depends.erase(si->depends.begin(), si->depends.end());      // MSVC.Netism
00710 
00711         // Iterate the list and compare shapes
00712 
00713         // Ok, 
00714         for (SortItem * si2 = items; si2 != si; ++si2)
00715         {
00716                 // Doesn't overlap
00717                 if (si2->occluded || !si->overlap(*si2)) continue;
00718 
00719                 // Attempt to find which is infront
00720                 if (*si < *si2)
00721                 {
00722                         // si2 occludes si (us)
00723                         if (si2->occl && si2->occludes(*si))
00724                         {
00725                                 // No need to do any more checks, this isn't visible
00726                                 si->occluded = true;
00727                                 break;
00728                         }
00729 
00730                         // si1 is behind si2, so add it to si2's dependency list
00731                         si2->depends.push_back(si);
00732                 }
00733                 else
00734                 {
00735                         // ss occludes si2. Sadly, we can't remove it from the list.
00736                         if (si->occl && si->occludes(*si2)) si2->occluded = true;
00737                         // si2 is behind si1, so add it to si1's dependency list
00738                         else si->depends.push_back(si2);
00739                 }
00740         }
00741 
00742         // Incrementing num_items adds the Item to the list
00743         num_items ++;
00744 }
00745 
00746 void ItemSorter::AddItem(Item *add)
00747 {
00748 #if 0
00749 
00750         sint32 x, y, z;
00751         add->getLerped(x, y, z);
00752         AddItem(x,y,z,add->getShape(), add->getFrame(), add->getFlags(), add->getObjId());
00753 
00754 #else
00755 
00756         //if (add->iz > skip_lift) return;
00757         //if (Application::tgwds && shape == 538) return;
00758 
00759         // First thing, get a SortItem to use
00760         
00761         if (num_items >= max_items)
00762         {
00763                 num_extra++;
00764                 return;
00765         }
00766 
00767         SortItem *si = items+num_items;
00768 
00769         si->item_num = add->getObjId();
00770         si->shape = add->getShapeObject();
00771         si->shape_num = add->getShape();
00772         si->frame = add->getFrame();
00773         ShapeFrame *frame = si->shape->getFrame(si->frame);
00774         if (!frame) {
00775                 perr << "Invalid shape: " << si->shape_num << "," << si->frame
00776                          << std::endl;
00777                 return;
00778         }
00779 
00780         ShapeInfo *info = add->getShapeInfo();
00781 
00782         //if (info->is_editor && !show_editor_items) return;
00783         //if (info->z > shape_max_height) return;
00784 
00785         // Dimensions
00786         sint32 xd, yd, zd;
00787         si->flags = add->getFlags();
00788         si->ext_flags = add->getExtFlags();
00789 
00790         // X and Y are flipped
00791         if (si->flags & Item::FLG_FLIPPED) 
00792         {
00793                 xd = info->y * 32;      // Multiply by 32 to get actual world size
00794                 yd = info->x * 32;      // Multiply by 32 to get actual world size
00795         }
00796         else
00797         {
00798                 xd = info->x * 32;      // Multiply by 32 to get actual world size
00799                 yd = info->y * 32;      // Multiply by 32 to get actual world size
00800         }
00801 
00802         zd = info->z * 8;       // Multiply by 8 to get actual world size
00803 
00804         // Worldspace bounding box
00805         add->getLerped(si->x, si->y, si->z);
00806         si->xleft = si->x - xd;
00807         si->yfar = si->y - yd;
00808         si->ztop = si->z + zd;
00809 
00810         // Screenspace bounding box left extent    (LNT x coord)
00811         si->sxleft = (si->xleft - si->y)/4 - cam_sx;
00812         // Screenspace bounding box right extent   (RFT x coord)
00813         si->sxright= (si->x - si->yfar)/4 - cam_sx;
00814 
00815         // Screenspace bounding box top x coord    (LFT x coord)
00816         si->sxtop = (si->xleft - si->yfar)/4 - cam_sx;
00817         // Screenspace bounding box top extent     (LFT y coord)
00818         si->sytop = (si->xleft + si->yfar)/8 - si->ztop - cam_sy;
00819 
00820         // Screenspace bounding box bottom x coord (RNB x coord)
00821         si->sxbot = (si->x - si->y)/4 - cam_sx;
00822         // Screenspace bounding box bottom extent  (RNB y coord)
00823         si->sybot = (si->x + si->y)/8 - si->z - cam_sy;
00824 
00825 //      si->sxleft += swo2;
00826 //      si->sxright += swo2;
00827 //      si->sxbot += swo2;
00828 //      si->sxtop += swo2;
00829 
00830 //      si->sytop += sho2;
00831 //      si->sybot += sho2;
00832 
00833         // Real Screenspace coords
00834         si->sx = si->sxbot - frame->xoff;       // Left
00835         si->sy = si->sybot - frame->yoff;       // Top
00836         si->sx2 = si->sx + frame->width;        // Right
00837         si->sy2 = si->sy + frame->height;       // Bottom
00838 
00839         // Do Clipping here
00840         si->clipped = surf->CheckClipped(Rect (si->sx,si->sy, frame->width, frame->height));
00841         if (si->clipped < 0) return;
00842 
00843         // These help out with sorting. We calc them now, so it will be faster
00844         si->f32x32 = xd==128 && yd==128;
00845         si->flat = zd == 0;
00846 
00847         /*
00848         if (Application::tgwds) {
00849                 si->draw = false;
00850                 si->solid = false;
00851                 si->occl = false;
00852                 si->roof = false;
00853                 si->noisy = false;
00854                 si->anim = false;
00855                 si->trans = false;
00856         }
00857         else
00858         */
00859         {
00860                 si->draw = info->is_draw();
00861                 si->solid = info->is_solid();
00862                 si->occl = info->is_occl() && !(si->flags & Item::FLG_INVISIBLE);
00863                 si->roof = info->is_roof();
00864                 si->noisy = info->is_noisy();
00865                 si->anim = info->animtype != 0;
00866                 si->trans = info->is_translucent();
00867                 si->fixed = info->is_fixed();
00868                 si->land = info->is_land();
00869         }
00870 
00871         si->occluded = false;
00872         si->order = -1;
00873 
00874         // We will clear all the vector memory
00875         // Stictly speaking the vector will sort of leak memory, since they
00876         // are never deleted
00877         //si->depends.clear();
00878         si->depends.erase(si->depends.begin(), si->depends.end());      // MSVC.Netism
00879 
00880         // Iterate the list and compare shapes
00881 
00882         // Ok, 
00883         for (SortItem * si2 = items; si2 != si; ++si2)
00884         {
00885                 // Doesn't overlap
00886                 if (si2->occluded || !si->overlap(*si2)) continue;
00887 
00888                 // Attempt to find which is infront
00889                 if (*si < *si2)
00890                 {
00891                         // si2 occludes ss
00892                         if (si2->occl && si2->occludes(*si))
00893                         {
00894                                 // No need to do any more checks, this isn't visible
00895                                 si->occluded = true;
00896                                 break;
00897                         }
00898 
00899                         // si1 is behind si2, so add it to si2's dependency list
00900                         si2->depends.push_back(si);
00901                 }
00902                 else
00903                 {
00904                         // ss occludes si2. Sadly, we can't remove it from the list.
00905                         if (si->occl && si->occludes(*si2)) si2->occluded = true;
00906                         // si2 is behind si1, so add it to si1's dependency list
00907                         else si->depends.push_back(si2);
00908                 }
00909         }
00910 
00911         // Incrementing num_items adds the Item to the list
00912         num_items ++;
00913 #endif
00914 }
00915 
00916 SortItem *prev = 0;
00917 
00918 void ItemSorter::PaintDisplayList(bool item_highlight)
00919 {
00920         prev = 0;
00921         SortItem *it = items;
00922         SortItem *end = items + num_items;
00923         order_counter = 0;      // Reset the order_counter
00924         while (it != end)
00925         {
00926                 if (it->order == -1) if (PaintSortItem(it)) return;
00927                 ++it;
00928         }
00929 
00930         // Item highlighting. We redraw each 'item' transparent
00931         if (item_highlight)
00932         {
00933                 it = items;
00934                 while (it != end)
00935                 {
00936                         if (!(it->flags & (Item::FLG_DISPOSABLE|Item::FLG_FAST_ONLY)) && !it->fixed )
00937                         {
00938                                 surf->PaintHighlightInvis(it->shape, 
00939                                                 it->frame, 
00940                                                 it->sxbot, 
00941                                                 it->sybot, 
00942                                                 it->trans, 
00943                                                 (it->flags&Item::FLG_FLIPPED)!=0, 0x1f00ffff);
00944                         }
00945 
00946                         ++it;
00947                 }
00948 
00949         }
00950 }
00951 
00952 bool ItemSorter::PaintSortItem(SortItem *si)
00953 {
00954         // Don't paint this, or dependencies if occluded
00955         if (si->occluded) return false;
00956 
00957         // Resursion, detection
00958         si->order = -2;
00959         
00960         // Iterate through our dependancies, and paint them, if possible
00961         SortItemVector::iterator it = si->depends.begin();
00962         SortItemVector::iterator end = si->depends.end();
00963         while (it != end)
00964         {
00965                 // Well, it can't. Implies infinite recursive sorting.
00966                 //if ((*it)->order == -2) CANT_HAPPEN_MSG("Detected cycle in the dependency graph");
00967 
00968                 if ((*it)->order == -1) if (PaintSortItem((*it))) return true;
00969 
00970                 ++it;
00971         }
00972 
00973         // Set our painting order
00974         si->order = order_counter;
00975         order_counter++;
00976 
00977         // Now paint us!
00978 
00979 //      if (wire) si->info->draw_box_back(s, dispx, dispy, 255);
00980 
00981         if (si->ext_flags & Item::EXT_HIGHLIGHT && (si->ext_flags & Item::EXT_TRANSPARENT || si->ext_flags & Item::EXT_TRANSPARENT))
00982                 surf->PaintHighlightInvis(si->shape, si->frame, si->sxbot, si->sybot, si->trans, (si->flags&Item::FLG_FLIPPED)!=0, 0x7F00007F);
00983         if (si->ext_flags & Item::EXT_HIGHLIGHT)
00984                 surf->PaintHighlight(si->shape, si->frame, si->sxbot, si->sybot, si->trans, (si->flags&Item::FLG_FLIPPED)!=0, 0x7F00007F);
00985         else if (si->ext_flags & Item::EXT_TRANSPARENT)
00986                 surf->PaintInvisible(si->shape, si->frame, si->sxbot, si->sybot, si->trans, (si->flags&Item::FLG_FLIPPED)!=0);
00987         else if (si->flags & Item::FLG_FLIPPED)
00988                 surf->PaintMirrored(si->shape, si->frame, si->sxbot, si->sybot, si->trans);
00989         else if (si->trans)
00990                 surf->PaintTranslucent(si->shape, si->frame, si->sxbot, si->sybot);
00991         else if (!si->clipped)
00992                 surf->PaintNoClip(si->shape, si->frame, si->sxbot, si->sybot);
00993         else
00994                 surf->Paint(si->shape, si->frame, si->sxbot, si->sybot);
00995                 
00996 //      if (wire) si->info->draw_box_front(s, dispx, dispy, 255);
00997 
00998         // weapon overlay
00999         // FIXME: use highlight/invisibility, also add to Trace() ?
01000         if (si->shape_num == 1 && si->item_num == 1) {
01001                 MainActor* av = getMainActor();
01002                 const WeaponOverlayFrame* wo_frame = 0;
01003                 uint32 wo_shapenum;
01004                 av->getWeaponOverlay(wo_frame, wo_shapenum);
01005                 if (wo_frame) {
01006                         Shape* wo_shape = GameData::get_instance()->getMainShapes()->getShape(wo_shapenum);
01007                         surf->Paint(wo_shape, wo_frame->frame,
01008                                                 si->sxbot + wo_frame->xoff,
01009                                                 si->sybot + wo_frame->yoff);
01010                 }
01011         }
01012 
01013         if (sort_limit) {
01014                 if (order_counter == sort_limit) {
01015                         static uint32 previt = 0;
01016                         int x1 = si->xleft;
01017                         int y1 = si->yfar;
01018                         int z2 = si->ztop;
01019                         if (!previt || previt != si->item_num)
01020                         {
01021                                 previt = si->item_num;
01022                                 pout << si->shape_num << ":" << si->frame << " (" << x1 << "," << y1 << "," << si->z << ") (" << si->x << "," << si->y << "," << z2 << ")" << std::endl;
01023                         //      ss->info->print();
01024                                 if (prev) *prev << *si;
01025                         }
01026                         return true;
01027                 }
01028                 prev = si;
01029         }
01030 
01031         return false;
01032 }
01033 
01034 bool ItemSorter::NullPaintSortItem(SortItem     *si)
01035 {
01036         // Don't paint this, or dependencies if occluded
01037         if (si->occluded) return false;
01038 
01039         // Resursion, detection
01040         si->order = -2;
01041         
01042         // Iterate through our dependancies, and paint them, if possible
01043         SortItemVector::iterator it = si->depends.begin();
01044         SortItemVector::iterator end = si->depends.end();
01045         while (it != end)
01046         {
01047                 // Well, it can't. Implies recursive sorting. Can happen though so
01048                 // you had best leave this commented out
01049                 //if ((*it)->order == -2) CANT_HAPPEN_MSG("Recursive item sorting");
01050 
01051                 if ((*it)->order == -1) if (NullPaintSortItem((*it))) return true;
01052 
01053                 ++it;
01054         }
01055 
01056         // Set our painting/sorting order
01057         si->order = order_counter;
01058         order_counter++;
01059 
01060         return false;
01061 }
01062 
01063 uint16 ItemSorter::Trace(sint32 x, sint32 y, HitFace* face, bool item_highlight)
01064 {
01065         SortItem *it;
01066         SortItem *end;
01067         SortItem *selected;
01068 
01069         if (!order_counter)     // If no order_counter we need to sort the items
01070         {
01071                 it = items;
01072                 end = items + num_items;
01073                 order_counter = 0;      // Reset the order_counter
01074                 while (it != end)
01075                 {
01076                         if (it->order == -1) if (NullPaintSortItem(it)) break;
01077 
01078                         ++it;
01079                 }
01080         }
01081 
01082         // Firstly, we check for highlighted items
01083         selected = 0;
01084 
01085         if (item_highlight)
01086         {
01087                 it = items + num_items;
01088                 selected = 0;
01089                 end = items;
01090 
01091                 while (it-- != end)
01092                 {
01093                         if (!(it->flags & (Item::FLG_DISPOSABLE|Item::FLG_FAST_ONLY)) && !it->fixed )
01094                         {
01095 
01096                                 if (!it->item_num) continue;
01097 
01098                                 // Doesn't Overlap
01099                                 if (x < it->sx || x >= it->sx2 || y < it->sy || y >= it->sy2) continue;
01100 
01101                                 // Now check the frame itself
01102                                 ShapeFrame *frame = it->shape->getFrame(it->frame);
01103                                 assert(frame); // invalid frames shouldn't have been added to the list
01104 
01105                                 // Nope, doesn't have a point
01106                                 if (it->flags & Item::FLG_FLIPPED)
01107                                 {
01108                                         if (!frame->hasPoint(it->sxbot-x, y-it->sybot)) continue;
01109                                 }
01110                                 else
01111                                 {
01112                                         if (!frame->hasPoint(x-it->sxbot, y-it->sybot)) continue;
01113                                 }
01114 
01115                                 // Ok now check against selected
01116                                 selected = it;
01117                         }       
01118                 }
01119 
01120         }
01121 
01122         // Ok, this is all pretty simple. We iterate all the items.
01123         // We then check to see if the item has a point where the trace goes.
01124         // Finally we then set the selected SortItem if it's 'order' is highest
01125         it = items;
01126         end = items + num_items;
01127 
01128         if (!selected) for (;it != end;++it)
01129         {
01130                 if (!it->item_num) continue;
01131 
01132                 // Doesn't Overlap
01133                 if (x < it->sx || x >= it->sx2 || y < it->sy || y >= it->sy2) continue;
01134 
01135                 // Now check the frame itself
01136                 ShapeFrame *frame = it->shape->getFrame(it->frame);
01137                 assert(frame); // invalid frames shouldn't have been added to the list
01138 
01139                 // Nope, doesn't have a point
01140                 if (it->flags & Item::FLG_FLIPPED)
01141                 {
01142                         if (!frame->hasPoint(it->sxbot-x, y-it->sybot)) continue;
01143                 }
01144                 else
01145                 {
01146                         if (!frame->hasPoint(x-it->sxbot, y-it->sybot)) continue;
01147                 }
01148 
01149                 // Ok now check against selected
01150                 if (!selected || (it->order > selected->order)) selected = it;
01151         }
01152 
01153         if (selected) {
01154 
01155                 if (face) {
01156                         // shortcut for zero-height items
01157                         if (selected->ztop == selected->z) {
01158                                 *face = Z_FACE;
01159                         } else {
01160                                 // determine face that was hit
01161 
01162                                 // RNT coordinates
01163                                 sint32 RNTx = selected->sxbot;
01164                                 sint32 RNTy = selected->sybot - selected->ztop + selected->z;
01165                                 
01166         /*
01167                                 Bounding Box layout (top part)
01168 
01169                    1    
01170                  /   \      
01171            /       \     1 = Left  Far  Top LFT --+
01172          2  Z-face   3   2 = Left  Near Top LNT -++
01173          | \       / |   3 = Right Far  Top RFT +-+
01174          |   \   /   |   4 = Right Near Top RNT +++
01175          | Y   4  X  |
01176          |face |face |
01177 
01178         */
01179 
01180                                 if (2 * (y - RNTy) <= (x - RNTx) && // if above/on line 4-3
01181                                         2 * (y - RNTy) < (RNTx - x)) // and above/on line 4-2
01182                                         *face = Z_FACE;
01183                                 else if (x > RNTx)
01184                                         *face = X_FACE;
01185                                 else
01186                                         *face = Y_FACE;
01187                         }
01188                 }
01189 
01190                 return selected->item_num;
01191         }
01192         
01193         return 0;
01194 }
01195 
01196 
01197 // End of file

Generated on Fri Jul 27 22:27:22 2007 for pentagram by  doxygen 1.4.7