Beispiel #1
0
			inline void set_index_data(const Uint32 index,
				const Uint32 data)
			{
				assert(index < get_index_count());
				assert((data < get_vertex_count()) ||
					((get_restart_index() == data) &&
						get_use_restart_index()));
				assert(index < m_indices.size());
				assert(get_index_count() == m_indices.size());

				m_indices[index] = data;

				assert(m_indices[index] == data);
			}
Beispiel #2
0
/**
 * \brief Constructs a state to render a given texture in a given mode.
 * \param texture_id The identifier of the texture to use when drawing.
 * \param shader The shader to use when drawing.
 * \param vertices The vertices to draw.
 * \param texture_coordinates The coordinates of the vertices in the texture.
 * \param c The color of the vertices.
 */
bear::visual::gl_state::gl_state
( GLuint texture_id, const shader_program& shader,
  const position_vector& texture_coordinates, const position_vector& vertices,
  const color_type& c )
  : m_mode( render_triangles ),
    m_shader( shader ), m_line_width( 0 )
{
  const position_vector v( polygon_to_triangles( vertices ) );

  push_vertices( v );
  push_texture_coordinates( polygon_to_triangles(texture_coordinates) );
  push_colors( c, v.size() );

  m_elements.push_back( element_range( texture_id, 0, get_vertex_count() ) );
} // gl_state::gl_state()
Beispiel #3
0
struct face *read_obj_file(const char *fname, int *count)
{
	FILE *fp;
	int n_v, n_f;
	struct vertex *vertex;
	struct face *face;

	fp = fopen(fname, "r");

	n_v = get_vertex_count(fp);
	vertex = (struct vertex *)malloc(n_v * sizeof(struct vertex));
	vertex_read(fp, vertex, n_v);
	n_f = get_face_count(fp);
	face = (struct face *)malloc(n_f * sizeof(struct face));
	face_read(fp, face, n_f, vertex, n_v);

	fclose(fp);
	free(vertex);
	*count = n_f;
	return face;
}
Beispiel #4
0
/**
 * \brief Draws the vertices in the case where there is no texture.
 */
void bear::visual::gl_state::draw_shape() const
{
  if ( m_vertices.empty() )
    return;

  enable_shader();

  if ( m_line_width > 0 )
    {
      glLineWidth( m_line_width );
      VISUAL_GL_ERROR_THROW();
    }

  set_colors();
  set_vertices();

  glBindTexture( GL_TEXTURE_2D, 0 );
  VISUAL_GL_ERROR_THROW();

  glDrawArrays( get_gl_render_mode(), 0, get_vertex_count() );

  disable_states();
} // gl_state::draw_shape()
// =======================================================================
// Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON
// Important: This function MUST be called before read_lines() 
// Otherwise we will loose all edges from faces (see read_lines() above)
//
// TODO: import uv set names
// ========================================================================
void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
	unsigned int i;
	
	allocate_poly_data(collada_mesh, me);

	UVDataWrapper uvs(collada_mesh->getUVCoords());
	VCOLDataWrapper vcol(collada_mesh->getColors());

	MPoly *mpoly = me->mpoly;
	MLoop *mloop = me->mloop;
	int loop_index = 0;

	MaterialIdPrimitiveArrayMap mat_prim_map;

	COLLADAFW::MeshPrimitiveArray& prim_arr = collada_mesh->getMeshPrimitives();
	COLLADAFW::MeshVertexData& nor = collada_mesh->getNormals();

	for (i = 0; i < prim_arr.getCount(); i++) {
		
		COLLADAFW::MeshPrimitive *mp = prim_arr[i];

		// faces
		size_t prim_totpoly                           = mp->getFaceCount();
		unsigned int *position_indices                = mp->getPositionIndices().getData();
		unsigned int *normal_indices                  = mp->getNormalIndices().getData();


		bool mp_has_normals = primitive_has_useable_normals(mp);
		bool mp_has_faces   = primitive_has_faces(mp);

		int collada_meshtype = mp->getPrimitiveType();
		
		// since we cannot set mpoly->mat_nr here, we store a portion of me->mpoly in Primitive
		Primitive prim = {mpoly, 0};

		// If MeshPrimitive is TRIANGLE_FANS we split it into triangles
		// The first trifan vertex will be the first vertex in every triangle
		// XXX The proper function of TRIANGLE_FANS is not tested!!!
		// XXX In particular the handling of the normal_indices looks very wrong to me
		if (collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLE_FANS) {
			unsigned grouped_vertex_count = mp->getGroupedVertexElementsCount();
			for (unsigned int group_index = 0; group_index < grouped_vertex_count; group_index++) {
				unsigned int first_vertex = position_indices[0]; // Store first trifan vertex
				unsigned int first_normal = normal_indices[0]; // Store first trifan vertex normal
				unsigned int vertex_count = mp->getGroupedVerticesVertexCount(group_index);

				for (unsigned int vertex_index = 0; vertex_index < vertex_count - 2; vertex_index++) {
					// For each triangle store indeces of its 3 vertices
					unsigned int triangle_vertex_indices[3] = {first_vertex, position_indices[1], position_indices[2]};
					set_poly_indices(mpoly, mloop, loop_index, triangle_vertex_indices, 3);

					if (mp_has_normals) {  // vertex normals, same inplementation as for the triangles
						// the same for vertces normals
						unsigned int vertex_normal_indices[3] = {first_normal, normal_indices[1], normal_indices[2]};
						if (!is_flat_face(vertex_normal_indices, nor, 3))
							mpoly->flag |= ME_SMOOTH;
						normal_indices++;
					}
				
					mpoly++;
					mloop += 3;
					loop_index += 3;
					prim.totpoly++;

				}

				// Moving cursor  to the next triangle fan.
				if (mp_has_normals)
					normal_indices += 2;

				position_indices +=  2;
			}
		}

		if (collada_meshtype == COLLADAFW::MeshPrimitive::POLYLIST ||
			collada_meshtype == COLLADAFW::MeshPrimitive::POLYGONS ||
			collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLES) {
			COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
			unsigned int start_index = 0;

			COLLADAFW::IndexListArray& index_list_array_uvcoord = mp->getUVCoordIndicesArray();
			COLLADAFW::IndexListArray& index_list_array_vcolor  = mp->getColorIndicesArray();

			for (unsigned int j = 0; j < prim_totpoly; j++) {
				
				// Vertices in polygon:
				int vcount = get_vertex_count(mpvc, j);
				set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount);


				for (unsigned int uvset_index = 0; uvset_index < index_list_array_uvcoord.getCount(); uvset_index++) {
					// get mtface by face index and uv set index
					COLLADAFW::IndexList& index_list = *index_list_array_uvcoord[uvset_index];
					MLoopUV  *mloopuv = (MLoopUV  *)CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, index_list.getName().c_str());
					if (mloopuv == NULL) {
						fprintf(stderr, "Collada import: Mesh [%s] : Unknown reference to TEXCOORD [#%s].\n", me->id.name, index_list.getName().c_str() );
					}
					else {
						set_face_uv(mloopuv+loop_index, uvs, start_index, *index_list_array_uvcoord[uvset_index], vcount);
					}
				}

				if (mp_has_normals) {
					if (!is_flat_face(normal_indices, nor, vcount))
						mpoly->flag |= ME_SMOOTH;
				}


				if (mp->hasColorIndices()) {
					int vcolor_count = index_list_array_vcolor.getCount();

					for (unsigned int vcolor_index = 0; vcolor_index < vcolor_count; vcolor_index++) {

						COLLADAFW::IndexList& color_index_list = *mp->getColorIndices(vcolor_index);
						COLLADAFW::String colname = extract_vcolname(color_index_list.getName());
						MLoopCol *mloopcol = (MLoopCol  *)CustomData_get_layer_named(&me->ldata, CD_MLOOPCOL, colname.c_str());
						if (mloopcol == NULL) {
							fprintf(stderr, "Collada import: Mesh [%s] : Unknown reference to VCOLOR [#%s].\n", me->id.name, color_index_list.getName().c_str());
						}
						else {
							set_vcol(mloopcol + loop_index, vcol, start_index, color_index_list, vcount);
						}
					}
				}

				mpoly++;
				mloop       += vcount;
				loop_index  += vcount;
				start_index += vcount;
				prim.totpoly++;

				if (mp_has_normals)
					normal_indices += vcount;

				position_indices += vcount;
			}
		}

		else if (collada_meshtype == COLLADAFW::MeshPrimitive::LINES) {
			continue; // read the lines later after all the rest is done
		}

		if (mp_has_faces)
			mat_prim_map[mp->getMaterialId()].push_back(prim);


	}

	geom_uid_mat_mapping_map[collada_mesh->getUniqueId()] = mat_prim_map;
}
// =================================================================
// Return the number of faces by summing up
// the facecounts of the parts.
// hint: This is done because mesh->getFacesCount() does
// count loose edges as extra faces, which is not what we want here.
// =================================================================
void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
	COLLADAFW::MeshPrimitiveArray& prim_arr = collada_mesh->getMeshPrimitives();
	int total_poly_count  = 0;
	int total_loop_count  = 0;

	// collect edge_count and face_count from all parts
	for (int i = 0; i < prim_arr.getCount(); i++) {
		COLLADAFW::MeshPrimitive *mp = prim_arr[i];
		int type = mp->getPrimitiveType();
		switch (type) {
			case COLLADAFW::MeshPrimitive::TRIANGLES:
			case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
			case COLLADAFW::MeshPrimitive::POLYLIST:
			case COLLADAFW::MeshPrimitive::POLYGONS:
			{
				COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
				size_t prim_poly_count    = mpvc->getFaceCount();

				size_t prim_loop_count    = 0;
				for (int index=0; index < prim_poly_count; index++) {
					prim_loop_count += get_vertex_count(mpvc, index);
				}

				total_poly_count += prim_poly_count;
				total_loop_count += prim_loop_count;

				break;
			}
			default:
				break;
		}
	}

	// Add the data containers
	if (total_poly_count > 0) {
		me->totpoly = total_poly_count;
		me->totloop = total_loop_count;
		me->mpoly   = (MPoly *)CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, me->totpoly);
		me->mloop   = (MLoop *)CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, me->totloop);

		unsigned int totuvset = collada_mesh->getUVCoords().getInputInfosArray().getCount();
		for (int i = 0; i < totuvset; i++) {
			if (collada_mesh->getUVCoords().getLength(i) == 0) {
				totuvset = 0;
				break;
			}
		}

		if (totuvset > 0) {
			for (int i = 0; i < totuvset; i++) {
				COLLADAFW::MeshVertexData::InputInfos *info = collada_mesh->getUVCoords().getInputInfosArray()[i];
				COLLADAFW::String &uvname = info->mName;
				// Allocate space for UV_data
				CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, uvname.c_str());
				CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, uvname.c_str());
			}
			// activate the first uv map
			me->mtpoly  = (MTexPoly *)CustomData_get_layer_n(&me->pdata, CD_MTEXPOLY, 0);
			me->mloopuv = (MLoopUV *) CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, 0);
		}

		int totcolset = collada_mesh->getColors().getInputInfosArray().getCount();
		if (totcolset > 0) {
			for (int i = 0; i < totcolset; i++) {
				COLLADAFW::MeshVertexData::InputInfos *info = collada_mesh->getColors().getInputInfosArray()[i];
				COLLADAFW::String colname = extract_vcolname(info->mName);
				CustomData_add_layer_named(&me->ldata,CD_MLOOPCOL,CD_DEFAULT,NULL,me->totloop, colname.c_str());
			}
			me->mloopcol = (MLoopCol *) CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, 0);
		}

	}
}
Beispiel #7
0
void Skeleton::update(unsigned long dt)
{
    const float delta = dt / 1000.0f;
    spSkeleton_update(skeleton_, delta);
    spAnimationState_update(state_, delta * time_scale_);
    spAnimationState_apply(state_, skeleton_);
    spSkeleton_updateWorldTransform(skeleton_);

    // This solution is not ideal. We iterate over the bones twice: First to
    // determine number of vertices, second to update the vertex buffer.
    num_vertices_ = get_vertex_count(skeleton_, &texture_);
    if (num_vertices_ > max_vertices_)
    {
        max_vertices_ = num_vertices_;
        vertices_ = std::make_unique<SpriteVertex[]>(max_vertices_);
    }

    size_t i = 0;
    for_each(skeleton_, [this, &i](spSlot* slot) {
        if (!slot->attachment)
            return;

        switch (slot->attachment->type)
        {
            case SP_ATTACHMENT_REGION: {
                float vertices[8];
                spRegionAttachment* region =
                    reinterpret_cast<spRegionAttachment*>(slot->attachment);
                R_ASSERT(texture_ == get_texture(region),
                         kErrorMultipleTexturesUnsupported);
                spRegionAttachment_computeWorldVertices(
                    region, slot->bone, vertices);

                const char r = skeleton_->r * slot->r * 0xff;
                const char g = skeleton_->g * slot->g * 0xff;
                const char b = skeleton_->b * slot->b * 0xff;
                const char a = skeleton_->a * slot->a * 0xff;

                vertices_[i].color.r = r;
                vertices_[i].color.g = g;
                vertices_[i].color.b = b;
                vertices_[i].color.a = a;
                vertices_[i].texcoord.x = region->uvs[SP_VERTEX_X1];
                vertices_[i].texcoord.y = region->uvs[SP_VERTEX_Y1];
                vertices_[i].position.x = vertices[SP_VERTEX_X1];
                vertices_[i].position.y = vertices[SP_VERTEX_Y1];

                vertices_[++i].color.r = r;
                vertices_[i].color.g = g;
                vertices_[i].color.b = b;
                vertices_[i].color.a = a;
                vertices_[i].texcoord.x = region->uvs[SP_VERTEX_X2];
                vertices_[i].texcoord.y = region->uvs[SP_VERTEX_Y2];
                vertices_[i].position.x = vertices[SP_VERTEX_X2];
                vertices_[i].position.y = vertices[SP_VERTEX_Y2];

                vertices_[++i].color.r = r;
                vertices_[i].color.g = g;
                vertices_[i].color.b = b;
                vertices_[i].color.a = a;
                vertices_[i].texcoord.x = region->uvs[SP_VERTEX_X3];
                vertices_[i].texcoord.y = region->uvs[SP_VERTEX_Y3];
                vertices_[i].position.x = vertices[SP_VERTEX_X3];
                vertices_[i].position.y = vertices[SP_VERTEX_Y3];

                ++i;
                vertices_[i] = vertices_[i - 1];

                vertices_[++i].color.r = r;
                vertices_[i].color.g = g;
                vertices_[i].color.b = b;
                vertices_[i].color.a = a;
                vertices_[i].texcoord.x = region->uvs[SP_VERTEX_X4];
                vertices_[i].texcoord.y = region->uvs[SP_VERTEX_Y4];
                vertices_[i].position.x = vertices[SP_VERTEX_X4];
                vertices_[i].position.y = vertices[SP_VERTEX_Y4];

                ++i;
                vertices_[i] = vertices_[i - 5];

                ++i;
                break;
            }
            case SP_ATTACHMENT_BOUNDING_BOX:
                break;
            case SP_ATTACHMENT_MESH: {
                spMeshAttachment* mesh =
                    reinterpret_cast<spMeshAttachment*>(slot->attachment);
                R_ASSERT(texture_ == get_texture(mesh),
                         kErrorMultipleTexturesUnsupported);
                i += update_mesh(&vertices_[i], skeleton_, mesh, slot);
                break;
            }
            case SP_ATTACHMENT_SKINNED_MESH: {
                spSkinnedMeshAttachment* mesh =
                    reinterpret_cast<spSkinnedMeshAttachment*>(
                        slot->attachment);
                R_ASSERT(texture_ == get_texture(mesh),
                         kErrorMultipleTexturesUnsupported);
                i += update_mesh(&vertices_[i], skeleton_, mesh, slot);
                break;
            }
        }
        if (slot->data->blendMode != SP_BLEND_MODE_NORMAL)  // TODO: Implement.
            LOGE("Non-normal blend mode not yet implemented");
    });

    vertex_buffer_.upload(vertices_.get(), i * sizeof(SpriteVertex));
}
Beispiel #8
0
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> D3D12GSRender::upload_vertex_attributes(
	const std::vector<std::pair<u32, u32> > &vertex_ranges,
	gsl::not_null<ID3D12GraphicsCommandList*> command_list)
{
	std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> vertex_buffer_views;
	command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertex_buffer_data.Get(), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, D3D12_RESOURCE_STATE_COPY_DEST));

	u32 vertex_count = get_vertex_count(vertex_ranges);
	size_t offset_in_vertex_buffers_buffer = 0;
	u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK];

	for (int index = 0; index < rsx::limits::vertex_count; ++index)
	{
		bool enabled = !!(input_mask & (1 << index));
		if (!enabled)
			continue;

		if (vertex_arrays_info[index].size > 0)
		{
			// Active vertex array
			const rsx::data_array_format_info &info = vertex_arrays_info[index];

			u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
			UINT buffer_size = element_size * vertex_count;
			size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);

			void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
			for (const auto &range : vertex_ranges)
			{
				write_vertex_array_data_to_buffer(mapped_buffer, range.first, range.second, index, info);
				mapped_buffer = (char*)mapped_buffer + range.second * element_size;
			}
			m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));

			command_list->CopyBufferRegion(m_vertex_buffer_data.Get(), offset_in_vertex_buffers_buffer, m_buffer_data.get_heap(), heap_offset, buffer_size);

			vertex_buffer_views.emplace_back(get_vertex_attribute_srv(info, offset_in_vertex_buffers_buffer, buffer_size));
			offset_in_vertex_buffers_buffer = get_next_multiple_of<48>(offset_in_vertex_buffers_buffer + buffer_size); // 48 is multiple of 2, 4, 6, 8, 12, 16

			m_timers.buffer_upload_size += buffer_size;

		}
		else if (register_vertex_info[index].size > 0)
		{
			// In register vertex attribute
			const rsx::data_array_format_info &info = register_vertex_info[index];
			const std::vector<u8> &data = register_vertex_data[index];

			u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
			UINT buffer_size = gsl::narrow<UINT>(data.size());
			size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);

			void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
			memcpy(mapped_buffer, data.data(), data.size());
			m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));

			command_list->CopyBufferRegion(m_vertex_buffer_data.Get(), offset_in_vertex_buffers_buffer, m_buffer_data.get_heap(), heap_offset, buffer_size);

			vertex_buffer_views.emplace_back(get_vertex_attribute_srv(info, offset_in_vertex_buffers_buffer, buffer_size));
			offset_in_vertex_buffers_buffer = get_next_multiple_of<48>(offset_in_vertex_buffers_buffer + buffer_size); // 48 is multiple of 2, 4, 6, 8, 12, 16
		}
	}
	command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertex_buffer_data.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));
	return vertex_buffer_views;
}
Beispiel #9
0
std::tuple<bool, size_t, std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC>> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list)
{
	if (draw_command == rsx::draw_command::inlined_array)
	{
		size_t vertex_count;
		std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> vertex_buffer_view;
		std::tie(vertex_buffer_view, vertex_count) = upload_inlined_vertex_array(
			vertex_arrays_info,
			{ (const gsl::byte*) inline_vertex_array.data(), gsl::narrow<int>(inline_vertex_array.size() * sizeof(uint)) },
			m_buffer_data, m_vertex_buffer_data.Get(), command_list);

		if (is_primitive_native(draw_mode))
			return std::make_tuple(false, vertex_count, vertex_buffer_view);

		D3D12_INDEX_BUFFER_VIEW index_buffer_view;
		size_t index_count;
		std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array({ { 0, (u32)vertex_count } });
		command_list->IASetIndexBuffer(&index_buffer_view);
		return std::make_tuple(true, index_count, vertex_buffer_view);
	}

	if (draw_command == rsx::draw_command::array)
	{
		if (is_primitive_native(draw_mode))
		{
			size_t vertex_count = get_vertex_count(first_count_commands);
			return std::make_tuple(false, vertex_count, upload_vertex_attributes(first_count_commands, command_list));
		}

		D3D12_INDEX_BUFFER_VIEW index_buffer_view;
		size_t index_count;
		std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array(first_count_commands);
		command_list->IASetIndexBuffer(&index_buffer_view);
		return std::make_tuple(true, index_count, upload_vertex_attributes(first_count_commands, command_list));
	}

	assert(draw_command == rsx::draw_command::indexed);

	// Index count
	size_t index_count = get_index_count(draw_mode, gsl::narrow<int>(get_vertex_count(first_count_commands)));

	rsx::index_array_type indexed_type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
	size_t index_size = get_index_type_size(indexed_type);

	// Alloc
	size_t buffer_size = align(index_count * index_size, 64);
	size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);

	void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
	u32 min_index, max_index;

	if (indexed_type == rsx::index_array_type::u16)
	{
		gsl::span<u16> dst = { (u16*)mapped_buffer, gsl::narrow<int>(buffer_size / index_size) };
		std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, draw_mode, first_count_commands);
	}

	if (indexed_type == rsx::index_array_type::u32)
	{
		gsl::span<u32> dst = { (u32*)mapped_buffer, gsl::narrow<int>(buffer_size / index_size) };
		std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, draw_mode, first_count_commands);
	}

	m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
	D3D12_INDEX_BUFFER_VIEW index_buffer_view = {
		m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset,
		(UINT)buffer_size,
		get_index_type(indexed_type)
	};
	m_timers.buffer_upload_size += buffer_size;
	command_list->IASetIndexBuffer(&index_buffer_view);

	return std::make_tuple(true, index_count, upload_vertex_attributes({ std::make_pair(0, max_index + 1) }, command_list));
}