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); }
/** * \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()
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; }
/** * \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); } } }
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)); }
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; }
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)); }