<commit_before>//
// Urho3D Engine
// Copyright (c) 2008-2011 <NAME>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "Precompiled.h"
#include "Context.h"
#include "Deserializer.h"
#include "Geometry.h"
#include "IndexBuffer.h"
#include "Log.h"
#include "Model.h"
#include "Profiler.h"
#include "Graphics.h"
#include "Serializer.h"
#include "VertexBuffer.h"

#include <cstring>

#include "DebugNew.h"

unsigned StoreOrLookupVertexBuffer(VertexBuffer* buffer, Vector<VertexBuffer*>& dest)
{
    for (unsigned i = 0; i < dest.Size(); ++i)
    {
        if (dest[i] == buffer)
            return i;
    }
    dest.Push(buffer);
    return dest.Size() - 1;
}

unsigned StoreOrLookupIndexBuffer(IndexBuffer* buffer, Vector<IndexBuffer*>& dest)
{
    for (unsigned i = 0; i < dest.Size(); ++i)
    {
        if (dest[i] == buffer)
            return i;
    }
    dest.Push(buffer);
    return dest.Size() - 1;
}

OBJECTTYPESTATIC(Model);

Model::Model(Context* context) :
    Resource(context)
{
}

Model::~Model()
{
}

void Model::RegisterObject(Context* context)
{
    context->RegisterFactory<Model>();
}

bool Model::Load(Deserializer& source)
{
    PROFILE(LoadModel);
    
    // Check ID
    if (source.ReadID() != "UMDL")
    {
        LOGERROR(source.GetName() + " is not a valid model file");
        return false;
    }
    
    geometries_.Clear();
    geometryBoneMappings_.Clear();
    morphs_.Clear();
    vertexBuffer_.Clear();
    indexBuffers_.Clear();
    
    SetMemoryUse(source.GetSize());
    
    // Read vertex buffers
    unsigned nuvertexBuffer_ = source.ReadUInt();
    for (unsigned i = 0; i < nuvertexBuffer_; ++i)
    {
        unsigned vertexCount = source.ReadUInt();
        unsigned elementMask = source.ReadUInt();
        unsigned morphStart = source.ReadUInt();
        unsigned morphCount = source.ReadUInt();
        
        SharedPtr<VertexBuffer> buffer(new VertexBuffer(context_));
        buffer->SetSize(vertexCount, elementMask);
        buffer->SetMorphRange(morphStart, morphCount);
        
        unsigned vertexSize = buffer->GetVertexSize();
        
        SharedArrayPtr<unsigned char> data(new unsigned char[vertexCount * vertexSize]);
        source.Read(data.GetPtr(), vertexCount * buffer->GetVertexSize());
        buffer->SetData(data.GetPtr());
        // If there is a morph range, make a copy of the data so that the morph range can be reset
        if (morphCount)
        {
            SharedArrayPtr<unsigned char> morphResetData(new unsigned char[morphCount * vertexSize]);
            memcpy(morphResetData.GetPtr(), &data[morphStart * vertexSize], morphCount * vertexSize);
            buffer->SetMorphRangeResetData(morphResetData);
        }
        
        vertexBuffer_.Push(buffer);
    }
    
    // Read index buffers
    unsigned nuindexBuffers_ = source.ReadUInt();
    for (unsigned i = 0; i < nuindexBuffers_; ++i)
    {
        unsigned indexCount = source.ReadUInt();
        unsigned indexSize = source.ReadUInt();
        
        SharedPtr<IndexBuffer> buffer(new IndexBuffer(context_));
        buffer->SetSize(indexCount, indexSize);
        SharedArrayPtr<unsigned char> data(new unsigned char[indexCount * indexSize]);
        source.Read(data.GetPtr(), indexCount * indexSize);
        buffer->SetData(data.GetPtr());
        
        indexBuffers_.Push(buffer);
    }
    
    // Read geometries
    unsigned numGeometries = source.ReadUInt();
    for (unsigned i = 0; i < numGeometries; ++i)
    {
        // Read bone mappings
        unsigned boneMappingCount = source.ReadUInt();
        PODVector<unsigned> boneMapping;
        for (unsigned j = 0; j < boneMappingCount; ++j)
            boneMapping.Push(source.ReadUInt());
        geometryBoneMappings_.Push(boneMapping);
        
        unsigned nulodLevels_ = source.ReadUInt();
        Vector<SharedPtr<Geometry> > geometryLodLevels;
        
        for (unsigned j = 0; j < nulodLevels_; ++j)
        {
            float distance = source.ReadFloat();
            PrimitiveType type = (PrimitiveType)source.ReadUInt();
        
            unsigned vertexBufferRef = source.ReadUInt();
            unsigned indexBufferRef = source.ReadUInt();
            unsigned indexStart = source.ReadUInt();
            unsigned indexCount = source.ReadUInt();
            
            if (vertexBufferRef >= vertexBuffer_.Size())
            {
                LOGERROR("Vertex buffer index out of bounds");
                return false;
            }
            if (indexBufferRef >= indexBuffers_.Size())
            {
                LOGERROR("Index buffer index out of bounds");
                return false;
            }
            
            SharedPtr<Geometry> geometry(new Geometry(context_));
            geometry->SetNumVertexBuffers(1);
            geometry->SetVertexBuffer(0, vertexBuffer_[vertexBufferRef]);
            geometry->SetIndexBuffer(indexBuffers_[indexBufferRef]);
            geometry->SetDrawRange(type, indexStart, indexCount);
            geometry->SetLodDistance(distance);
            
            geometryLodLevels.Push(geometry);
        }
        
        geometries_.Push(geometryLodLevels);
    }
    
    // Read morphs
    unsigned numorphs_ = source.ReadUInt();
    for (unsigned i = 0; i < numorphs_; ++i)
    {
        ModelMorph newMorph;
        
        newMorph.name_ = source.ReadString();
        newMorph.nameHash_ = StringHash(newMorph.name_);
        newMorph.weight_ = 0.0f;
        unsigned nubuffers_ = source.ReadUInt();
        
        for (unsigned j = 0; j < nubuffers_; ++j)
        {
            VertexBufferMorph newBuffer;
            unsigned bufferIndex = source.ReadUInt();
            
            newBuffer.elementMask_ = source.ReadUInt();
            newBuffer.vertexCount_ = source.ReadUInt();
            
            // Base size: size of each vertex index
            unsigned vertexSize = sizeof(unsigned);
            // Add size of individual elements
            if (newBuffer.elementMask_ & MASK_POSITION)
                vertexSize += sizeof(Vector3);
            if (newBuffer.elementMask_ & MASK_NORMAL)
                vertexSize += sizeof(Vector3);
            if (newBuffer.elementMask_ & MASK_TANGENT)<commit_msg>Load model data directly into the vertex buffer instead of doing an intermediate copy.<commit_after>//
// Urho3D Engine
// Copyright (c) 2008-2011 <NAME>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "Precompiled.h"
#include "Context.h"
#include "Deserializer.h"
#include "Geometry.h"
#include "IndexBuffer.h"
#include "Log.h"
#include "Model.h"
#include "Profiler.h"
#include "Graphics.h"
#include "Serializer.h"
#include "VertexBuffer.h"

#include <cstring>

#include "DebugNew.h"

unsigned StoreOrLookupVertexBuffer(VertexBuffer* buffer, Vector<VertexBuffer*>& dest)
{
    for (unsigned i = 0; i < dest.Size(); ++i)
    {
        if (dest[i] == buffer)
            return i;
    }
    dest.Push(buffer);
    return dest.Size() - 1;
}

unsigned StoreOrLookupIndexBuffer(IndexBuffer* buffer, Vector<IndexBuffer*>& dest)
{
    for (unsigned i = 0; i < dest.Size(); ++i)
    {
        if (dest[i] == buffer)
            return i;
    }
    dest.Push(buffer);
    return dest.Size() - 1;
}

OBJECTTYPESTATIC(Model);

Model::Model(Context* context) :
    Resource(context)
{
}

Model::~Model()
{
}

void Model::RegisterObject(Context* context)
{
    context->RegisterFactory<Model>();
}

bool Model::Load(Deserializer& source)
{
    PROFILE(LoadModel);
    
    // Check ID
    if (source.ReadID() != "UMDL")
    {
        LOGERROR(source.GetName() + " is not a valid model file");
        return false;
    }
    
    geometries_.Clear();
    geometryBoneMappings_.Clear();
    morphs_.Clear();
    vertexBuffer_.Clear();
    indexBuffers_.Clear();
    
    SetMemoryUse(source.GetSize());
    
    // Read vertex buffers
    unsigned numVertexBuffers = source.ReadUInt();
    for (unsigned i = 0; i < numVertexBuffers; ++i)
    {
        unsigned vertexCount = source.ReadUInt();
        unsigned elementMask = source.ReadUInt();
        unsigned morphStart = source.ReadUInt();
        unsigned morphCount = source.ReadUInt();
        
        SharedPtr<VertexBuffer> buffer(new VertexBuffer(context_));
        buffer->SetSize(vertexCount, elementMask);
        buffer->SetMorphRange(morphStart, morphCount);
        
        unsigned vertexSize = buffer->GetVertexSize();
        unsigned char* data = (unsigned char*)buffer->Lock(0, vertexCount, LOCK_NORMAL);
        if (data)
        {
            source.Read(data, vertexCount * vertexSize);
            // If there is a morph range, make a copy of the data so that the morph range can be reset
            if (morphCount)
            {
                SharedArrayPtr<unsigned char> morphResetData(new unsigned char[morphCount * vertexSize]);
                memcpy(morphResetData.GetPtr(), &data[morphStart * vertexSize], morphCount * vertexSize);
                buffer->SetMorphRangeResetData(morphResetData);
            }
            buffer->Unlock();
        }
        else
            return false;
        
        vertexBuffer_.Push(buffer);
    }
    
    // Read index buffers
    unsigned numIndexBuffers = source.ReadUInt();
    for (unsigned i = 0; i < numIndexBuffers; ++i)
    {
        unsigned indexCount = source.ReadUInt();
        unsigned indexSize = source.ReadUInt();
        
        SharedPtr<IndexBuffer> buffer(new IndexBuffer(context_));
        buffer->SetSize(indexCount, indexSize);
        
        unsigned char* data = (unsigned char*)buffer->Lock(0, indexCount, LOCK_NORMAL);
        if (data)
        {
            source.Read(data, indexCount * indexSize);
            buffer->Unlock();
        }
        else
            return false;
        
        indexBuffers_.Push(buffer);
    }
    
    // Read geometries
    unsigned numGeometries = source.ReadUInt();
    for (unsigned i = 0; i < numGeometries; ++i)
    {
        // Read bone mappings
        unsigned boneMappingCount = source.ReadUInt();
        PODVector<unsigned> boneMapping;
        for (unsigned j = 0; j < boneMappingCount; ++j)
            boneMapping.Push(source.ReadUInt());
        geometryBoneMappings_.Push(boneMapping);
        
        unsigned numLodLevels = source.ReadUInt();
        Vector<SharedPtr<Geometry> > geometryLodLevels;
        
        for (unsigned j = 0; j < numLodLevels; ++j)
        {
            float distance = source.ReadFloat();
            PrimitiveType type = (PrimitiveType)source.ReadUInt();
            
            unsigned vertexBufferRef = source.ReadUInt();
            unsigned indexBufferRef = source.ReadUInt();
            unsigned indexStart = source.ReadUInt();
            unsigned indexCount = source.ReadUInt();
            
            if (vertexBufferRef >= vertexBuffer_.Size())
            {
                LOGERROR("Vertex buffer index out of bounds");
                return false;
            }
            if (indexBufferRef >= indexBuffers_.Size())
            {
                LOGERROR("Index buffer index out of bounds");
                return false;
            }
            
            SharedPtr<Geometry> geometry(new Geometry(context_));
            geometry->SetNumVertexBuffers(1);
            geometry->SetVertexBuffer(0, vertexBuffer_[vertexBufferRef]);
            geometry->SetIndexBuffer(indexBuffers_[indexBufferRef]);
            geometry->SetDrawRange(type, indexStart, indexCount);
            geometry->SetLodDistance(distance);
            
            geometryLodLevels.Push(geometry);
        }
        
        geometries_.Push(geometryLodLevels);
    }
    
    // Read morphs
    unsigned numMorphs = source.ReadUInt();
    for (unsigned i = 0; i < numMorphs; ++i)
    {
        ModelMorph newMorph;
        
        newMorph.name_ = source.ReadString();
        newMorph.nameHash_ = StringHash(newMorph.name_);
        newMorph.weight_ = 0.0f;
        unsigned nubuffers_ = source.ReadUInt();
        
        for (unsigned j = 0; j < nubuffers_; ++j)
        {
            VertexBufferMorph newBuffer;
            unsigned bufferIndex = source.ReadUInt();
            
            newBuffer.elementMask_ = source.ReadUInt();
            newBuffer.vertexCount_ = source.ReadUInt();
            
            // Base size: size of each vertex index
            unsigned vertexSize = sizeof(unsigned);
            // Add size of individual elements
            if (newBuffer.elementMask_ & MASK_POSITION)
                vertexSize += sizeof(Vector3);
            if (newBuffer.elementMask_ & MASK_NORMAL)
                vertexSize += sizeof(Vector3);
            if (newBuffer.elementMask_ & MASK_TANGENT)
{'fraction_non_alphanumeric': 0.10490361853229625, 'fraction_numerical': 0.003652350355089618, 'mean_word_length': 2.3819762122598354, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 62, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4859650', 'n_tokens_mistral': 4088, 'n_tokens_neox': 3979, 'n_words': 1116}