diff --git a/src/bsp/Bsp.cpp b/src/bsp/Bsp.cpp index 73e68cf0..66ce6677 100644 --- a/src/bsp/Bsp.cpp +++ b/src/bsp/Bsp.cpp @@ -2114,7 +2114,7 @@ STRUCTCOUNT Bsp::remove_unused_model_structures(unsigned int target) { nodes[i].iPlane = remap.planes[nodes[i].iPlane]; if (nodes[i].nFaces > 0) - nodes[i].firstFace = remap.faces[nodes[i].firstFace]; + nodes[i].iFirstFace = remap.faces[nodes[i].iFirstFace]; for (int k = 0; k < 2; k++) { if (nodes[i].iChildren[k] >= 0) @@ -2882,7 +2882,7 @@ void Bsp::write(const std::string& path) freenodes16[n].iChildren[1] = (short)nodes[n].iChildren[1]; freenodes16[n].iPlane = nodes[n].iPlane; - freenodes16[n].firstFace = (unsigned short)nodes[n].firstFace; + freenodes16[n].firstFace = (unsigned short)nodes[n].iFirstFace; freenodes16[n].nFaces = (unsigned short)nodes[n].nFaces; for (int m = 0; m < 3; m++) { @@ -2902,7 +2902,7 @@ void Bsp::write(const std::string& path) freenodes32a[n].iChildren[1] = nodes[n].iChildren[1]; freenodes32a[n].iPlane = nodes[n].iPlane; - freenodes32a[n].firstFace = nodes[n].firstFace; + freenodes32a[n].firstFace = nodes[n].iFirstFace; freenodes32a[n].nFaces = nodes[n].nFaces; for (int m = 0; m < 3; m++) { @@ -3385,7 +3385,7 @@ bool Bsp::load_lumps(std::string fpath) for (int n = 0; n < nodeCount; n++) { - tmpnodes[n].firstFace = nodes16[n].firstFace; + tmpnodes[n].iFirstFace = nodes16[n].firstFace; tmpnodes[n].iChildren[0] = nodes16[n].iChildren[0]; tmpnodes[n].iChildren[1] = nodes16[n].iChildren[1]; tmpnodes[n].iPlane = nodes16[n].iPlane; @@ -3426,7 +3426,7 @@ bool Bsp::load_lumps(std::string fpath) for (int n = 0; n < nodeCount; n++) { - tmpnodes[n].firstFace = nodes16[n].firstFace; + tmpnodes[n].iFirstFace = nodes16[n].firstFace; tmpnodes[n].iChildren[0] = nodes16[n].iChildren[0]; tmpnodes[n].iChildren[1] = nodes16[n].iChildren[1]; tmpnodes[n].iPlane = nodes16[n].iPlane; @@ -4090,7 +4090,7 @@ bool Bsp::validate() } for (int i = 0; i < leafCount; i++) { - if (leaves[i].nMarkSurfaces > 0 && leaves[i].iFirstMarkSurface >= marksurfCount) + if (leaves[i].nMarkSurfaces > 0 && leaves[i].iFirstMarkSurface + leaves[i].nMarkSurfaces > marksurfCount) { print_log(PRINT_RED | PRINT_INTENSITY, get_localized_string(LANG_0117), i, leaves[i].iFirstMarkSurface, marksurfCount); isValid = false; @@ -4125,9 +4125,9 @@ bool Bsp::validate() } for (int i = 0; i < nodeCount; i++) { - if (nodes[i].nFaces > 0 && nodes[i].firstFace >= faceCount) + if (nodes[i].nFaces > 0 && nodes[i].iFirstFace >= faceCount) { - print_log(PRINT_RED | PRINT_INTENSITY, get_localized_string(LANG_0120), i, nodes[i].firstFace, faceCount); + print_log(PRINT_RED | PRINT_INTENSITY, get_localized_string(LANG_0120), i, nodes[i].iFirstFace, faceCount); isValid = false; } if (nodes[i].iPlane >= planeCount) @@ -4738,7 +4738,7 @@ void Bsp::mark_node_structures(int iNode, STRUCTUSAGE* usage, bool skipLeaves) for (int i = 0; i < node.nFaces; i++) { - mark_face_structures(node.firstFace + i, usage); + mark_face_structures(node.iFirstFace + i, usage); } for (int i = 0; i < 2; i++) @@ -4844,7 +4844,7 @@ void Bsp::remap_node_structures(int iNode, STRUCTREMAP* remap) for (int i = 0; i < node.nFaces; i++) { - remap_face_structures(node.firstFace + i, remap); + remap_face_structures(node.iFirstFace + i, remap); } for (int i = 0; i < 2; i++) @@ -5796,7 +5796,7 @@ void Bsp::create_node_box(const vec3& min, const vec3& max, BSPMODEL* targetMode { BSPNODE32& node = newNodes[nodeCount + k]; - node.firstFace = (startFace + k); // face required for decals + node.iFirstFace = (startFace + k); // face required for decals node.nFaces = 1; node.iPlane = startPlane + k; // node mins/maxs don't matter for submodels. Leave them at 0. @@ -5979,7 +5979,7 @@ void Bsp::create_nodes(Solid& solid, BSPMODEL* targetModel) { BSPNODE32& node = newNodes[nodeCount + k]; - node.firstFace = (startFace + k); // face required for decals + node.iFirstFace = (startFace + k); // face required for decals node.nFaces = 1; node.iPlane = startPlane + k; // node mins/maxs don't matter for submodels. Leave them at 0. @@ -6320,7 +6320,7 @@ void Bsp::copy_bsp_model(int modelIdx, Bsp* targetMap, STRUCTREMAP& remap, std:: for (size_t i = 0; i < newNodes.size(); i++) { BSPNODE32& node = newNodes[i]; - node.firstFace = remap.faces[node.firstFace]; + node.iFirstFace = remap.faces[node.iFirstFace]; node.iPlane = remap.planes[node.iPlane]; for (int k = 0; k < 2; k++) @@ -6486,6 +6486,121 @@ int Bsp::duplicate_model(int modelIdx) return newModelIdx; } +bool Bsp::remove_face(int faceIdx, bool onlyleafs) +{ + // Check if face is valid + if (faceIdx < 0 || faceIdx >= faceCount) + { + return false; + } + + int leafFaceTarget = -1; + + if (onlyleafs) + { + leafFaceTarget = faceIdx; + } + else + { + print_log("Remove face with id:{}\n", faceIdx); + std::vector all_faces; + for (int f = 0; f < faceCount; f++) + { + if (f != faceIdx) + { + all_faces.push_back(faces[f]); + } + else + { + // Shift face count in models + for (int m = 0; m < modelCount; m++) + { + if (models[m].nFaces == 0) + continue; + if (faceIdx >= models[m].iFirstFace && faceIdx < models[m].iFirstFace + models[m].nFaces) + { + print_log("Remove face from {} model\n", m); + models[m].nFaces--; + } + else if (models[m].iFirstFace != 0 && models[m].iFirstFace > faceIdx) + { + models[m].iFirstFace--; + } + } + + // Shift face count in nodes + for (int n = 0; n < nodeCount; n++) + { + if (nodes[n].nFaces == 0) + continue; + if (faceIdx >= nodes[n].iFirstFace && faceIdx < nodes[n].iFirstFace + nodes[n].nFaces) + { + print_log("Remove face from {} node\n", n); + nodes[n].nFaces--; + } + else if (nodes[n].iFirstFace != 0 && nodes[n].iFirstFace > faceIdx) + { + nodes[n].iFirstFace--; + } + } + + //Shift face count in marksurfs + for (int s = 0; s < marksurfCount; s++) + { + if (marksurfs[s] == 0) + continue; + + if (faceIdx == marksurfs[s]) + { + print_log("Remove face from {} surface\n", s); + marksurfs[s] = leafFaceTarget; + } + else if (marksurfs[s] != 0 && marksurfs[s] > faceIdx) + { + marksurfs[s]--; + } + } + } + } + + // Update faces array + unsigned char* newLump = new unsigned char[sizeof(BSPFACE32) * all_faces.size()]; + memcpy(newLump, &all_faces[0], sizeof(BSPFACE32) * all_faces.size()); + replace_lump(LUMP_FACES, newLump, sizeof(BSPFACE32) * all_faces.size()); + } + + std::vector all_mark_surfaces; + for (int s = 0; s < marksurfCount; s++) + { + if (marksurfs[s] != leafFaceTarget) + { + all_mark_surfaces.push_back(marksurfs[s]); + } + else + { + for (int m = 0; m < leafCount; m++) + { + if (leaves[m].nMarkSurfaces == 0) + continue; + if (s >= leaves[m].iFirstMarkSurface && s < leaves[m].iFirstMarkSurface + leaves[m].nMarkSurfaces) + { + print_log("Remove face {} from {} leaf\n", faceIdx, m); + leaves[m].nMarkSurfaces--; + } + else if (leaves[m].iFirstMarkSurface != 0 && leaves[m].iFirstMarkSurface > s) + { + leaves[m].iFirstMarkSurface--; + } + } + } + } + + unsigned char *newLump = new unsigned char[sizeof(int) * all_mark_surfaces.size()]; + memcpy(newLump, &all_mark_surfaces[0], sizeof(int) * all_mark_surfaces.size()); + replace_lump(LUMP_MARKSURFACES, newLump, sizeof(int) * all_mark_surfaces.size()); + return true; +} + int Bsp::merge_two_models(int src_model, int dst_model) { if (models[dst_model].iFirstFace > models[src_model].iFirstFace) @@ -6517,9 +6632,9 @@ int Bsp::merge_two_models(int src_model, int dst_model) for (int m = 0; m < nodeCount; m++) { - if (nodes[m].firstFace >= models[dst_model].iFirstFace + models[dst_model].nFaces) + if (nodes[m].iFirstFace >= models[dst_model].iFirstFace + models[dst_model].nFaces) { - nodes[m].firstFace += newfaces; + nodes[m].iFirstFace += newfaces; } } diff --git a/src/bsp/Bsp.h b/src/bsp/Bsp.h index b061ce35..6ff7b270 100644 --- a/src/bsp/Bsp.h +++ b/src/bsp/Bsp.h @@ -251,6 +251,8 @@ class Bsp int duplicate_model(int modelIdx); void duplicate_model_structures(int modelIdx); + + bool remove_face(int faceid, bool onlyleafs = false); int merge_two_models(int src_model, int dst_model); // if the face's texinfo is not unique, a new one is created and returned. Otherwise, it's current texinfo is returned diff --git a/src/bsp/BspMerger.cpp b/src/bsp/BspMerger.cpp index de359cfa..dfa9eaea 100644 --- a/src/bsp/BspMerger.cpp +++ b/src/bsp/BspMerger.cpp @@ -1566,9 +1566,9 @@ void BspMerger::merge_nodes(Bsp& mapA, Bsp& mapB) } } } - if (node.nFaces && node.firstFace >= thisWorldFaceCount) + if (node.nFaces && node.iFirstFace >= thisWorldFaceCount) { - node.firstFace += otherFaceCount; + node.iFirstFace += otherFaceCount; } mergedNodes.push_back(node); @@ -1593,7 +1593,7 @@ void BspMerger::merge_nodes(Bsp& mapA, Bsp& mapB) node.iPlane = planeRemap[node.iPlane]; if (node.nFaces) { - node.firstFace += thisWorldFaceCount; + node.iFirstFace += thisWorldFaceCount; } mergedNodes.push_back(node); diff --git a/src/bsp/bsptypes.h b/src/bsp/bsptypes.h index e868e13e..973950e0 100644 --- a/src/bsp/bsptypes.h +++ b/src/bsp/bsptypes.h @@ -139,6 +139,8 @@ enum MODEL_SORT_MODES SORT_MODES }; +/* main */ + struct BSPLUMP { int nOffset; // File offset to data @@ -149,7 +151,6 @@ struct BSPLUMP } }; - struct BSPHEADER { int nVersion; // Must be 30 for a valid HL BSP file @@ -160,23 +161,6 @@ struct BSPHEADER } }; -struct BSPHEADER_EX -{ - int id; // must be little endian XASH - int nVersion; - BSPLUMP lump[EXTRA_LUMPS]; - BSPHEADER_EX() - { - id = 0; - nVersion = 0; - } -}; - -struct LumpState -{ - std::vector lumps[HEADER_LUMPS]; -}; - struct BSPPLANE { vec3 vNormal; @@ -199,14 +183,6 @@ struct BSPPLANE } }; -struct CSGPLANE -{ - double normal[3]; - double origin[3]; - double dist; - int nType; -}; - struct BSPTEXTUREINFO { vec3 vS; @@ -217,10 +193,6 @@ struct BSPTEXTUREINFO int nFlags; }; -bool operator < (const BSPTEXTUREINFO& struct1, const BSPTEXTUREINFO& struct2); -bool operator > (const BSPTEXTUREINFO& struct1, const BSPTEXTUREINFO& struct2); -bool operator ==(const BSPTEXTUREINFO& struct1, const BSPTEXTUREINFO& struct2); - struct BSPMIPTEX { @@ -229,16 +201,6 @@ struct BSPMIPTEX int nOffsets[MIPLEVELS]; // Offsets to texture mipmaps, relative to the start of this structure }; -struct BSPFACE16 -{ - unsigned short iPlane; // Plane the face is parallel to - short nPlaneSide; // Set if different normals orientation - int iFirstEdge; // Index of the first surfedge - short nEdges; // Number of consecutive surfedges - short iTextureInfo; // Index of the texture info structure - unsigned char nStyles[MAX_LIGHTMAPS]; // Specify lighting styles - int nLightmapOffset; // Offsets into the raw lightmap data -}; struct BSPFACE32 { @@ -251,17 +213,6 @@ struct BSPFACE32 int nLightmapOffset; // Offsets into the raw lightmap data }; -struct BSPLEAF16 -{ - int nContents; // Contents enumeration - int nVisOffset; // Offset into the visibility lump - short nMins[3], nMaxs[3]; // Defines bounding box - unsigned short iFirstMarkSurface; - unsigned short nMarkSurfaces; // Index and count into marksurfaces array - unsigned char nAmbientLevels[MAX_AMBIENTS]; // Ambient sound levels - - bool isEmpty(); -}; struct BSPLEAF32 { @@ -276,6 +227,95 @@ struct BSPLEAF32 bool isEmpty(); }; +struct BSPEDGE32 +{ + int iVertex[2]; // Indices into vertex array + + BSPEDGE32(); + BSPEDGE32(unsigned int v1, unsigned int v2); +}; + +struct BSPMODEL +{ + vec3 nMins; + vec3 nMaxs; + vec3 vOrigin; // Coordinates to move the // coordinate system + int iHeadnodes[MAX_MAP_HULLS]; // Index into nodes array + int nVisLeafs; // ??? + int iFirstFace, nFaces; // Index and count into faces +}; + +struct BSPNODE32 +{ + int iPlane; + int iChildren[2]; // negative numbers are -(leafs+1), not nodes + float nMins[3]; // for sphere culling + float nMaxs[3]; + int iFirstFace; + int nFaces; // counting both sides +}; + +struct BSPCLIPNODE32 +{ + int iPlane; // Index into planes + int iChildren[2]; // negative numbers are contents +}; + +/* other */ + +bool operator < (const BSPTEXTUREINFO& struct1, const BSPTEXTUREINFO& struct2); +bool operator > (const BSPTEXTUREINFO& struct1, const BSPTEXTUREINFO& struct2); +bool operator ==(const BSPTEXTUREINFO& struct1, const BSPTEXTUREINFO& struct2); + + +struct CSGPLANE +{ + double normal[3]; + double origin[3]; + double dist; + int nType; +}; + +struct BSPHEADER_EX +{ + int id; // must be little endian XASH + int nVersion; + BSPLUMP lump[EXTRA_LUMPS]; + BSPHEADER_EX() + { + id = 0; + nVersion = 0; + } +}; + +struct LumpState +{ + std::vector lumps[HEADER_LUMPS]; +}; + +struct BSPFACE16 +{ + unsigned short iPlane; // Plane the face is parallel to + short nPlaneSide; // Set if different normals orientation + int iFirstEdge; // Index of the first surfedge + short nEdges; // Number of consecutive surfedges + short iTextureInfo; // Index of the texture info structure + unsigned char nStyles[MAX_LIGHTMAPS]; // Specify lighting styles + int nLightmapOffset; // Offsets into the raw lightmap data +}; + +struct BSPLEAF16 +{ + int nContents; // Contents enumeration + int nVisOffset; // Offset into the visibility lump + short nMins[3], nMaxs[3]; // Defines bounding box + unsigned short iFirstMarkSurface; + unsigned short nMarkSurfaces; // Index and count into marksurfaces array + unsigned char nAmbientLevels[MAX_AMBIENTS]; // Ambient sound levels + + bool isEmpty(); +}; + struct BSPLEAF32A { int nContents; @@ -298,24 +338,6 @@ struct BSPEDGE16 BSPEDGE16(unsigned short v1, unsigned short v2); }; -struct BSPEDGE32 -{ - int iVertex[2]; // Indices into vertex array - - BSPEDGE32(); - BSPEDGE32(unsigned int v1, unsigned int v2); -}; - -struct BSPMODEL -{ - vec3 nMins; - vec3 nMaxs; - vec3 vOrigin; // Coordinates to move the // coordinate system - int iHeadnodes[MAX_MAP_HULLS]; // Index into nodes array - int nVisLeafs; // ??? - int iFirstFace, nFaces; // Index and count into faces -}; - struct BSPNODE16 { int iPlane; // Index into Planes lump @@ -324,16 +346,6 @@ struct BSPNODE16 unsigned short firstFace, nFaces; // Index and count into Faces }; -struct BSPNODE32 -{ - int iPlane; - int iChildren[2]; // negative numbers are -(leafs+1), not nodes - float nMins[3]; // for sphere culling - float nMaxs[3]; - int firstFace; - int nFaces; // counting both sides -}; - struct BSPNODE32A { int iPlane; @@ -350,11 +362,6 @@ struct BSPCLIPNODE16 short iChildren[2]; // negative numbers are contents }; -struct BSPCLIPNODE32 -{ - int iPlane; // Index into planes - int iChildren[2]; // negative numbers are contents -}; /* * application types (not part of the BSP) diff --git a/src/editor/BspRenderer.cpp b/src/editor/BspRenderer.cpp index b427b1b6..022d8201 100644 --- a/src/editor/BspRenderer.cpp +++ b/src/editor/BspRenderer.cpp @@ -1054,13 +1054,13 @@ int BspRenderer::refreshModel(int modelIdx, bool refreshClipnodes, bool noTriang memcpy(renderGroups[i].wireframeVerts, &renderGroupWireframeVerts[i][0], renderGroups[i].wireframeVertCount * sizeof(cVert)); auto tmpBuf = renderGroups[i].buffer = new VertexBuffer(g_app->bspShader, 0, GL_TRIANGLES); + tmpBuf->addAttribute(POS_3F, "vPosition"); tmpBuf->addAttribute(TEX_2F, "vTex"); tmpBuf->addAttribute(3, GL_FLOAT, 0, "vLightmapTex0"); tmpBuf->addAttribute(3, GL_FLOAT, 0, "vLightmapTex1"); tmpBuf->addAttribute(3, GL_FLOAT, 0, "vLightmapTex2"); tmpBuf->addAttribute(3, GL_FLOAT, 0, "vLightmapTex3"); tmpBuf->addAttribute(4, GL_FLOAT, 0, "vColor"); - tmpBuf->addAttribute(POS_3F, "vPosition"); tmpBuf->setData(renderGroups[i].verts, renderGroups[i].vertCount); renderGroups[i].wireframeBuffer = new VertexBuffer(g_app->colorShader, COLOR_4B | POS_3F, renderGroups[i].wireframeVerts, renderGroups[i].wireframeVertCount, GL_LINES); diff --git a/src/editor/Gui.cpp b/src/editor/Gui.cpp index 040375ee..cc70848f 100644 --- a/src/editor/Gui.cpp +++ b/src/editor/Gui.cpp @@ -894,6 +894,9 @@ void Gui::drawBspContexMenu() map->getBspRender()->preRenderEnts(); map->update_lump_pointers(); map->update_ent_lump(); + + + map->getBspRender()->pushModelUndoState("MERGE MODEL [DEBUG]", EDIT_MODEL_LUMPS); } } if (ImGui::BeginMenu(get_localized_string(LANG_0466).c_str(), !app->isLoading)) @@ -8701,6 +8704,55 @@ void Gui::drawFaceEditorWidget() updatedFaceVec = true; } } + + ImVec4 errorColor = { 1.0, 0.0, 0.0, 1.0 }; + ImGui::PushStyleColor(ImGuiCol_Text, errorColor); + if (ImGui::Button("REMOVE")) + { + map->remove_face(app->pickInfo.selectedFaces[0], false); + + map->getBspRender()->loadLightmaps(); + map->getBspRender()->calcFaceMaths(); + map->getBspRender()->preRenderFaces(); + map->getBspRender()->preRenderEnts(); + + map->update_lump_pointers(); + map->update_ent_lump(); + + + map->getBspRender()->pushModelUndoState("REMOVE FACE", EDIT_MODEL_LUMPS); + } + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::TextUnformatted("Face now totally removed from map!"); + ImGui::EndTooltip(); + } + ImGui::SameLine(); + + if (ImGui::Button("REMOVE PVS")) + { + map->remove_face(app->pickInfo.selectedFaces[0], true); + + map->getBspRender()->loadLightmaps(); + map->getBspRender()->calcFaceMaths(); + map->getBspRender()->preRenderFaces(); + map->getBspRender()->preRenderEnts(); + + map->update_lump_pointers(); + map->update_ent_lump(); + + + map->getBspRender()->pushModelUndoState("REMOVE FACE FROM PVS", EDIT_MODEL_LUMPS); + } + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::TextUnformatted("Face will be removed from leaves and now only invisibled!"); + ImGui::EndTooltip(); + } + ImGui::PopStyleColor(); + } if (app->pickInfo.selectedFaces.size() > 1) diff --git a/src/gl/primitives.h b/src/gl/primitives.h index efbc5f85..2768787c 100644 --- a/src/gl/primitives.h +++ b/src/gl/primitives.h @@ -9,8 +9,9 @@ struct tVert { - float u, v; vec3 pos; + // texture coordinates + float u, v; tVert() = default; tVert(float x, float y, float z, float u, float v) : u(u), v(v), pos(x, y, z) @@ -23,31 +24,29 @@ struct tVert struct modelVert { + vec3 pos; // texture coordinates float u, v; - vec3 pos; }; struct lightmapVert { + vec3 pos; // texture coordinates float u, v; - // lightmap texture coordinates // last value scales the lightmap brightness float luv[MAX_LIGHTMAPS][3]; - // color float r, g, b, a; - - vec3 pos; }; struct cVert { - COLOR4 c; vec3 pos; + COLOR4 c; + cVert() = default; cVert(float x, float y, float z, COLOR4 c) : c(c), pos(x, y, z) {} diff --git a/src/gl/shaders.cpp b/src/gl/shaders.cpp index 2d45ee2b..22d0b991 100644 --- a/src/gl/shaders.cpp +++ b/src/gl/shaders.cpp @@ -11,8 +11,8 @@ namespace Shaders "uniform vec4 colorMult;\n" // vertex variables - "attribute vec4 vColor;\n" "attribute vec3 vPosition;\n" + "attribute vec4 vColor;\n" // fragment variables "varying vec4 fColor;\n" @@ -41,8 +41,8 @@ namespace Shaders "uniform mat4 modelViewProjection;\n" // vertex variables - "attribute vec2 vTex;\n" "attribute vec3 vPosition;\n" + "attribute vec2 vTex;\n" // fragment variables "varying vec2 fTex;\n" @@ -71,8 +71,8 @@ namespace Shaders "uniform mat4 modelViewProjection;\n" // vertex variables - "attribute vec2 vTex;\n" "attribute vec3 vPosition;\n" + "attribute vec2 vTex;\n" // fragment variables "varying vec2 fTex;\n" @@ -100,13 +100,13 @@ namespace Shaders "uniform mat4 modelViewProjection;\n" // vertex variables + "attribute vec3 vPosition;\n" "attribute vec2 vTex;\n" "attribute vec3 vLightmapTex0;\n" "attribute vec3 vLightmapTex1;\n" "attribute vec3 vLightmapTex2;\n" "attribute vec3 vLightmapTex3;\n" "attribute vec4 vColor;\n" - "attribute vec3 vPosition;\n" // fragment variables "varying vec2 fTex;\n" diff --git a/src/mdl/mdl_studio.cpp b/src/mdl/mdl_studio.cpp index d7e76621..ff4215c3 100644 --- a/src/mdl/mdl_studio.cpp +++ b/src/mdl/mdl_studio.cpp @@ -684,8 +684,8 @@ void StudioModel::RefreshMeshList(int body) for (int j = 0; j < m_pmodel->nummesh; j++) { auto tmpBuf = mdl_mesh_groups[body][j].buffer = new VertexBuffer(g_app->modelShader, 0, GL_TRIANGLES); - tmpBuf->addAttribute(TEX_2F, "vTex"); tmpBuf->addAttribute(POS_3F, "vPosition"); + tmpBuf->addAttribute(TEX_2F, "vTex"); } }