OpenSubdiv/opensubdiv/osdutil/drawController.h

180 lines
7.2 KiB
C++

//
// Copyright 2013 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
#ifndef OSDUTIL_DRAW_CONTROLLER_H
#define OSDUTIL_DRAW_CONTROLLER_H
#include "../version.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
/*
concept DrawDelegate
{
void Begin();
void End();
void Bind(OsdUtilMeshBatchBase<DRAW_CONTEXT> *batch, EffectHandle effect);
void DrawElements(OsdDrawContext::PatchArray const &patchArray);
bool IsCombinable(EffectHandle &a, EffectHandle &b)
}
*/
namespace OsdUtil {
// ------------------------------------------------------------------------
// DrawCollection
// ------------------------------------------------------------------------
template <typename DRAW_ITEM_COLLECTION, typename DRAW_DELEGATE>
void DrawCollection(DRAW_ITEM_COLLECTION const &items, DRAW_DELEGATE *delegate) {
delegate->Begin();
// iterate over DrawItemCollection
for (typename DRAW_ITEM_COLLECTION::const_iterator it = items.begin(); it != items.end(); ++it) {
delegate->Bind(it->GetBatch(), it->GetEffect());
// iterate over sub items within a draw item
OsdDrawContext::PatchArrayVector const &patchArrays = it->GetPatchArrays();
for (OsdDrawContext::PatchArrayVector::const_iterator pit = patchArrays.begin(); pit != patchArrays.end(); ++pit) {
delegate->DrawElements(*pit);
}
delegate->Unbind(it->GetBatch(), it->GetEffect());
}
delegate->End();
}
// ------------------------------------------------------------------------
struct PatchArrayCombiner {
typedef std::map<OsdDrawContext::PatchDescriptor, OsdDrawContext::PatchArrayVector> Dictionary;
struct PatchArrayComparator {
bool operator() (OsdDrawContext::PatchArray const &a, OsdDrawContext::PatchArray const &b) {
return a.GetDescriptor() < b.GetDescriptor() or ((a.GetDescriptor() == b.GetDescriptor()) and
(a.GetVertIndex() < b.GetVertIndex()));
}
};
// XXX: reconsider this function
template <typename DRAW_ITEM_COLLECTION, typename BATCH, typename EFFECT_HANDLE>
void emit(DRAW_ITEM_COLLECTION &result, BATCH *batch, EFFECT_HANDLE &effect) {
if (dictionary.empty()) return;
typename DRAW_ITEM_COLLECTION::value_type item(batch, effect);
for (Dictionary::iterator it = dictionary.begin(); it != dictionary.end(); ++it) {
if (it->second.empty()) continue;
// expecting patchArrays is already sorted mostly.
std::sort(it->second.begin(), it->second.end(), PatchArrayComparator());
for (OsdDrawContext::PatchArrayVector::iterator pit = it->second.begin(); pit != it->second.end(); ++pit) {
if (not item.GetPatchArrays().empty()) {
OsdDrawContext::PatchArray &back = item.GetPatchArrays().back();
if (back.GetDescriptor() == pit->GetDescriptor() &&
back.GetVertIndex() + back.GetNumIndices() == pit->GetVertIndex()) {
// combine together
back.SetNumPatches(back.GetNumPatches() + pit->GetNumPatches());
continue;
}
}
// append to item
item.GetPatchArrays().push_back(*pit);
}
}
result.push_back(item);
for (Dictionary::iterator it = dictionary.begin(); it != dictionary.end(); ++it) {
it->second.clear();
}
}
void append(OsdDrawContext::PatchArray const &patchArray) {
dictionary[patchArray.GetDescriptor()].push_back(patchArray);
}
Dictionary dictionary;
};
// ------------------------------------------------------------------------
// OptimizeDrawItem
// ------------------------------------------------------------------------
template <typename DRAW_ITEM_COLLECTION, typename DRAW_DELEGATE>
void OptimizeDrawItem(DRAW_ITEM_COLLECTION const &items,
DRAW_ITEM_COLLECTION &result,
DRAW_DELEGATE *delegate) {
typedef typename DRAW_ITEM_COLLECTION::value_type DrawItem;
if (items.empty()) return;
result.reserve(items.size());
typename DrawItem::BatchBase *currentBatch = items[0].GetBatch();
typename DrawItem::EffectHandle const *currentEffect = &(items[0].GetEffect());
PatchArrayCombiner combiner;
for (typename DRAW_ITEM_COLLECTION::const_iterator it = items.begin(); it != items.end(); ++it) {
typename DrawItem::BatchBase *batch = it->GetBatch();
typename DrawItem::EffectHandle const &effect = it->GetEffect();
if (currentBatch != batch or
(not delegate->IsCombinable(*currentEffect, effect))) {
// emit cached draw item
combiner.emit(result, currentBatch, *currentEffect);
currentBatch = batch;
currentEffect = &effect;
}
// merge consecutive items if possible. This operation changes drawing order.
// i.e.
// PrimA-Regular, PrimA-Transition, PrimB-Regular, PrimB-Transition
// becomes
// PrimA-Regular, PrimB-Regular, PrimA-Transition, PrimB-Transition
OsdDrawContext::PatchArrayVector const &patchArrays = it->GetPatchArrays();
for (OsdDrawContext::PatchArrayVector::const_iterator itp = patchArrays.begin(); itp != patchArrays.end(); ++itp) {
if (itp->GetNumPatches() == 0) continue;
// insert patchArrays into dictionary
combiner.append(*itp);
}
}
// pick up after
combiner.emit(result, currentBatch, *currentEffect);
}
};
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* OSDUTIL_DRAW_CONTROLLER_H */