mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-14 16:01:08 +00:00
180 lines
7.2 KiB
C++
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 */
|