/* This file is part of reicast. reicast is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. reicast is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with reicast. If not, see . */ #include "sorter.h" #include struct IndexTrig { u32 id[3]; u16 pid; f32 z; }; #if 0 static float min3(float v0, float v1, float v2) { return std::min(std::min(v0, v1), v2); } static float max3(float v0, float v1, float v2) { return std::max(std::max(v0, v1), v2); } #endif static float minZ(const Vertex *v, const u32 *mod) { return std::min(std::min(v[mod[0]].z, v[mod[1]].z), v[mod[2]].z); } static bool operator<(const IndexTrig& left, const IndexTrig& right) { return left.zcount<2) { pp->zvZ=0; } else { u32* idx = idx_base + pp->first; Vertex* vtx=vtx_base+idx[0]; Vertex* vtx_end=vtx_base + idx[pp->count-1]+1; u32 zv=0xFFFFFFFF; while(vtx!=vtx_end) { zv = std::min(zv, (u32&)vtx->z); vtx++; } pp->zvZ=(f32&)zv; } pp++; } std::stable_sort(pvrrc.global_param_tr.head() + first, pvrrc.global_param_tr.head() + first + count); } const static Vertex *vtx_sort_base; #if 0 /* Per triangle sorting experiments */ //approximate the triangle area float area_x2(Vertex* v) { return 2/3*fabs( (v[0].x-v[2].x)*(v[1].y-v[0].y) - (v[0].x-v[1].x)*(v[2].y-v[0].y)) ; } //approximate the distance ^2 float distance_apprx(Vertex* a, Vertex* b) { float xd=a->x-b->x; float yd=a->y-b->y; return xd*xd+yd*yd; } //was good idea, but not really working .. bool Intersect(Vertex* a, Vertex* b) { float a1=area_x2(a); float a2=area_x2(b); float d = distance_apprx(a,b); return (a1+a1)>d; } //root for quick-union u16 rid(vector& v, u16 id) { while(id!=v[id]) id=v[id]; return id; } struct TrigBounds { float xs,xe; float ys,ye; float zs,ze; }; //find 3d bounding box for triangle TrigBounds bound(Vertex* v) { TrigBounds rv = { std::min(std::min(v[0].x, v[1].x), v[2].x), std::max(std::max(v[0].x,v[1].x),v[2].x), std::min(std::min(v[0].y, v[1].y), v[2].y), std::max(std::max(v[0].y,v[1].y),v[2].y), std::min(std::min(v[0].z, v[1].z), v[2].z), std::max(std::max(v[0].z,v[1].z),v[2].z), }; return rv; } //bounding box 2d intersection bool Intersect(TrigBounds& a, TrigBounds& b) { return ( !(a.xeb.xe) && !(a.yeb.ye) /*&& !(a.zeb.ze)*/ ); } bool operator<(const IndexTrig &left, const IndexTrig &right) { /* TrigBounds l=bound(vtx_sort_base+left.id); TrigBounds r=bound(vtx_sort_base+right.id); if (!Intersect(l,r)) { return true; } else { return (l.zs + l.ze) < (r.zs + r.ze); }*/ return minZ(&vtx_sort_base[left.id])pcw.full & PCW_DRAW_MASK) == (pp1->pcw.full & PCW_DRAW_MASK) && pp0->isp.full == pp1->isp.full && pp0->tcw.full == pp1->tcw.full && pp0->tsp.full == pp1->tsp.full && pp0->tileclip == pp1->tileclip; } static void fill_id(u32 *d, const Vertex *v0, const Vertex *v1, const Vertex *v2, const Vertex *vb) { d[0] = (u32)(v0 - vb); d[1] = (u32)(v1 - vb); d[2] = (u32)(v2 - vb); } void GenSorted(int first, int count, std::vector& pidx_sort, std::vector& vidx_sort) { u32 tess_gen=0; pidx_sort.clear(); if (pvrrc.verts.used() == 0 || count == 0) return; const Vertex * const vtx_base = pvrrc.verts.head(); const u32 * const idx_base = pvrrc.idx.head(); const PolyParam * const pp_base = &pvrrc.global_param_tr.head()[first]; const PolyParam *pp = pp_base; const PolyParam * const pp_end = pp + count; while (pp->count == 0 && pp < pp_end) pp++; if (pp == pp_end) return; vtx_sort_base=vtx_base; static u32 vtx_cnt; int vtx_count = pvrrc.verts.used() - idx_base[pp->first]; if ((u32)vtx_count > vtx_cnt) vtx_cnt = vtx_count; #if PRINT_SORT_STATS printf("TVTX: %d || %d\n",vtx_cnt,vtx_count); #endif if (vtx_count<=0) return; //make lists of all triangles, with their pid and vid static std::vector lst; lst.resize(vtx_count*4); int pfsti=0; while(pp!=pp_end) { u32 ppid = (u32)(pp - pp_base); if (pp->count>2) { const u32 *idx = idx_base + pp->first; u32 flip = 0; for (u32 i = 0; i < pp->count - 2; i++) { const Vertex *v0, *v1; if (flip) { v0 = vtx_base + idx[i + 1]; v1 = vtx_base + idx[i]; } else { v0 = vtx_base + idx[i]; v1 = vtx_base + idx[i + 1]; } const Vertex *v2 = vtx_base + idx[i + 2]; #if 0 const Vertex *v3, *v4, *v5; if (settings.pvr.subdivide_transp) { u32 tess_x=(max3(v0->x,v1->x,v2->x)-min3(v0->x,v1->x,v2->x))/32; u32 tess_y=(max3(v0->y,v1->y,v2->y)-min3(v0->y,v1->y,v2->y))/32; if (tess_x==1) tess_x=0; if (tess_y==1) tess_y=0; //bool tess=(maxZ(v0,v1,v2)/minZ(v0,v1,v2))>=1.2; if (tess_x + tess_y) { v3=pvrrc.verts.Append(3); v4=v3+1; v5=v4+1; //xyz for (int i=0;i<3;i++) { ((float*)&v3->x)[i]=((float*)&v0->x)[i]*0.5f+((float*)&v2->x)[i]*0.5f; ((float*)&v4->x)[i]=((float*)&v0->x)[i]*0.5f+((float*)&v1->x)[i]*0.5f; ((float*)&v5->x)[i]=((float*)&v1->x)[i]*0.5f+((float*)&v2->x)[i]*0.5f; } //*TODO* Make it perspective correct //uv for (int i=0;i<2;i++) { ((float*)&v3->u)[i]=((float*)&v0->u)[i]*0.5f+((float*)&v2->u)[i]*0.5f; ((float*)&v4->u)[i]=((float*)&v0->u)[i]*0.5f+((float*)&v1->u)[i]*0.5f; ((float*)&v5->u)[i]=((float*)&v1->u)[i]*0.5f+((float*)&v2->u)[i]*0.5f; } //color for (int i=0;i<4;i++) { v3->col[i]=v0->col[i]/2+v2->col[i]/2; v4->col[i]=v0->col[i]/2+v1->col[i]/2; v5->col[i]=v1->col[i]/2+v2->col[i]/2; } fill_id(lst[pfsti].id,v0,v3,v4,vtx_base); lst[pfsti].pid= ppid ; lst[pfsti].z = minZ(vtx_base,lst[pfsti].id); pfsti++; fill_id(lst[pfsti].id,v2,v3,v5,vtx_base); lst[pfsti].pid= ppid ; lst[pfsti].z = minZ(vtx_base,lst[pfsti].id); pfsti++; fill_id(lst[pfsti].id,v3,v4,v5,vtx_base); lst[pfsti].pid= ppid ; lst[pfsti].z = minZ(vtx_base,lst[pfsti].id); pfsti++; fill_id(lst[pfsti].id,v5,v4,v1,vtx_base); lst[pfsti].pid= ppid ; lst[pfsti].z = minZ(vtx_base,lst[pfsti].id); pfsti++; tess_gen+=3; } else { fill_id(lst[pfsti].id,v0,v1,v2,vtx_base); lst[pfsti].pid= ppid ; lst[pfsti].z = minZ(vtx_base,lst[pfsti].id); pfsti++; } } else #endif { fill_id(lst[pfsti].id,v0,v1,v2,vtx_base); lst[pfsti].pid= ppid ; lst[pfsti].z = minZ(vtx_base,lst[pfsti].id); pfsti++; } flip ^= 1; } } pp++; } u32 aused=pfsti; lst.resize(aused); //sort them #if 1 std::stable_sort(lst.begin(),lst.end()); //Merge pids/draw cmds if two different pids are actually equal if (true) { for (u32 k=1;klst[k].pid) { //MOVE UP for (int j=k;j>0 && lst[j].pid!=lst[j-1].pid && !Intersect(lst[j],lst[j-1]);j--) { swap(lst[j],lst[j-1]); } } else { //move down for (int j=k+1;j