diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index aafe95129..86750fc32 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -694,6 +694,7 @@ file( GLOB HEADER_FILES
 	polyrenderer/scene/*.h
 	hwrenderer/data/*.h
 	hwrenderer/dynlights/*.h
+	hwrenderer/models/*.h
 	hwrenderer/postprocessing/*.h
 	hwrenderer/scene/*.h
 	hwrenderer/textures/*.h
@@ -1041,7 +1042,6 @@ set (PCH_SOURCES
 	gl/data/gl_viewpointbuffer.cpp
 	gl/dynlights/gl_lightbuffer.cpp
 	gl/dynlights/gl_shadowmap.cpp
-	gl/models/gl_models.cpp
 	gl/renderer/gl_renderer.cpp
 	gl/renderer/gl_renderstate.cpp
 	gl/renderer/gl_renderbuffers.cpp
@@ -1060,6 +1060,7 @@ set (PCH_SOURCES
 	hwrenderer/data/flatvertices.cpp
 	hwrenderer/dynlights/hw_aabbtree.cpp
 	hwrenderer/dynlights/hw_shadowmap.cpp
+	hwrenderer/models/hw_models.cpp
 	hwrenderer/scene/hw_skydome.cpp
 	hwrenderer/postprocessing/hw_postprocess.cpp
 	hwrenderer/postprocessing/hw_postprocess_cvars.cpp
@@ -1418,7 +1419,6 @@ source_group("OpenGL Loader" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl
 source_group("OpenGL Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/.+")
 source_group("OpenGL Renderer\\Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/data/.+")
 source_group("OpenGL Renderer\\Dynamic Lights" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/dynlights/.+")
-source_group("OpenGL Renderer\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/models/.+")
 source_group("OpenGL Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/renderer/.+")
 source_group("OpenGL Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/scene/.+")
 source_group("OpenGL Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/shaders/.+")
diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h
index 60bee5a58..b888c91f3 100644
--- a/src/gl/renderer/gl_renderstate.h
+++ b/src/gl/renderer/gl_renderstate.h
@@ -105,8 +105,8 @@ public:
 	void ResetVertexBuffer()
 	{
 		// forces rebinding with the next 'apply' call.
-		mVertexBuffer = nullptr;
-		mIndexBuffer = nullptr;
+		mCurrentVertexBuffer = nullptr;
+		mCurrentIndexBuffer = nullptr;
 	}
 
 	void SetSpecular(float glossiness, float specularLevel)
diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp
index d5551d13c..e096b3e4a 100644
--- a/src/gl/scene/gl_drawinfo.cpp
+++ b/src/gl/scene/gl_drawinfo.cpp
@@ -43,7 +43,7 @@
 #include "gl/renderer/gl_renderer.h"
 #include "gl/data/gl_viewpointbuffer.h"
 #include "gl/dynlights/gl_lightbuffer.h"
-#include "gl/models/gl_models.h"
+#include "hwrenderer/models/hw_models.h"
 
 class FDrawInfoList
 {
@@ -243,12 +243,14 @@ void FDrawInfo::DrawModel(GLSprite *spr, FRenderState &state)
 {
 	FGLModelRenderer renderer(this, state, spr->dynlightindex);
 	renderer.RenderModel(spr->x, spr->y, spr->z, spr->modelframe, spr->actor, Viewpoint.TicFrac);
+	GLRenderer->mVBO->Bind(state);
 }
 
 void FDrawInfo::DrawHUDModel(HUDSprite *huds, FRenderState &state)
 {
 	FGLModelRenderer renderer(this, state, huds->lightindex);
 	renderer.RenderHUDModel(huds->weapon, huds->mx, huds->my);
+	GLRenderer->mVBO->Bind(state);
 }
 
 void FDrawInfo::RenderPortal(HWPortal *p, bool usestencil)
diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp
index 7fadb2c8e..780d494ec 100644
--- a/src/gl/system/gl_framebuffer.cpp
+++ b/src/gl/system/gl_framebuffer.cpp
@@ -39,7 +39,7 @@
 #include "hwrenderer/utility/hw_clock.h"
 #include "hwrenderer/utility/hw_vrmodes.h"
 #include "gl/data/gl_uniformbuffer.h"
-#include "gl/models/gl_models.h"
+#include "hwrenderer/models/hw_models.h"
 #include "gl/shaders/gl_shaderprogram.h"
 #include "gl_debug.h"
 #include "r_videoscale.h"
diff --git a/src/gl/models/gl_models.cpp b/src/hwrenderer/models/hw_models.cpp
similarity index 92%
rename from src/gl/models/gl_models.cpp
rename to src/hwrenderer/models/hw_models.cpp
index 13ee5ade4..b6df1ee20 100644
--- a/src/gl/models/gl_models.cpp
+++ b/src/hwrenderer/models/hw_models.cpp
@@ -22,11 +22,10 @@
 /*
 ** gl_models.cpp
 **
-** OpenGL renderer model handling code
+** hardware renderer model handling code
 **
 **/
 
-#include "gl_load/gl_system.h"
 #include "w_wad.h"
 #include "g_game.h"
 #include "doomstat.h"
@@ -39,12 +38,10 @@
 #include "hwrenderer/textures/hw_material.h"
 #include "hwrenderer/data/vertexbuffer.h"
 #include "hwrenderer/data/flatvertices.h"
-
-#include "gl_load/gl_interface.h"
-#include "gl/renderer/gl_renderer.h"
-#include "gl/scene/gl_drawinfo.h"
-#include "gl/models/gl_models.h"
-#include "gl/shaders/gl_shader.h"
+#include "hwrenderer/scene/hw_drawinfo.h"
+#include "hwrenderer/scene/hw_renderstate.h"
+#include "hwrenderer/scene/hw_portal.h"
+#include "hw_models.h"
 
 CVAR(Bool, gl_light_models, true, CVAR_ARCHIVE)
 
@@ -110,11 +107,6 @@ IModelVertexBuffer *FGLModelRenderer::CreateVertexBuffer(bool needindex, bool si
 	return new FModelVertexBuffer(needindex, singleframe);
 }
 
-void FGLModelRenderer::ResetVertexBuffer()
-{
-	GLRenderer->mVBO->Bind(state);
-}
-
 void FGLModelRenderer::SetInterpolation(double inter)
 {
 	state.SetInterpolationFactor((float)inter);
@@ -223,9 +215,7 @@ void FModelVertexBuffer::UnlockIndexBuffer()
 
 void FModelVertexBuffer::SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size)
 {
-	mIndexFrame[0] = frame1;
-	mIndexFrame[1] = frame2;
-	auto state = static_cast<FGLModelRenderer*>(renderer)->state;
-	state.SetVertexBuffer(mVertexBuffer, mIndexFrame[0], mIndexFrame[1]);
+	auto &state = static_cast<FGLModelRenderer*>(renderer)->state;
+	state.SetVertexBuffer(mVertexBuffer, frame1, frame2);
 	if (mIndexBuffer) state.SetIndexBuffer(mIndexBuffer);
 }
diff --git a/src/gl/models/gl_models.h b/src/hwrenderer/models/hw_models.h
similarity index 92%
rename from src/gl/models/gl_models.h
rename to src/hwrenderer/models/hw_models.h
index 01d596879..4d2086acf 100644
--- a/src/gl/models/gl_models.h
+++ b/src/hwrenderer/models/hw_models.h
@@ -28,12 +28,11 @@
 #include "r_data/models/models.h"
 
 class GLSprite;
-struct FDrawInfo;
+struct HWDrawInfo;
 class FRenderState;
 
 class FModelVertexBuffer : public IModelVertexBuffer
 {
-	int mIndexFrame[2];
 	IVertexBuffer *mVertexBuffer;
 	IIndexBuffer *mIndexBuffer;
 
@@ -55,16 +54,15 @@ class FGLModelRenderer : public FModelRenderer
 {
 	friend class FModelVertexBuffer;
 	int modellightindex = -1;
-	FDrawInfo *di;
+	HWDrawInfo *di;
 	FRenderState &state;
 public:
-	FGLModelRenderer(FDrawInfo *d, FRenderState &st, int mli) : modellightindex(mli), di(d), state(st)
+	FGLModelRenderer(HWDrawInfo *d, FRenderState &st, int mli) : modellightindex(mli), di(d), state(st)
 	{}
 	ModelRendererType GetType() const override { return GLModelRendererType; }
 	void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
 	void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) override;
 	IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override;
-	void ResetVertexBuffer() override;
 	VSMatrix GetViewToWorldMatrix() override;
 	void BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
 	void EndDrawHUDModel(AActor *actor) override;
diff --git a/src/hwrenderer/scene/hw_renderstate.h b/src/hwrenderer/scene/hw_renderstate.h
index 7f39bf79b..dcba861ba 100644
--- a/src/hwrenderer/scene/hw_renderstate.h
+++ b/src/hwrenderer/scene/hw_renderstate.h
@@ -399,6 +399,7 @@ public:
 
 	void SetVertexBuffer(IVertexBuffer *vb, int offset0, int offset1)
 	{
+		assert(vb);
 		mVertexBuffer = vb;
 		mVertexOffsets[0] = offset0;
 		mVertexOffsets[1] = offset1;
diff --git a/src/polyrenderer/scene/poly_model.cpp b/src/polyrenderer/scene/poly_model.cpp
index 4b5cccf62..28288504e 100644
--- a/src/polyrenderer/scene/poly_model.cpp
+++ b/src/polyrenderer/scene/poly_model.cpp
@@ -143,10 +143,6 @@ IModelVertexBuffer *PolyModelRenderer::CreateVertexBuffer(bool needindex, bool s
 	return new PolyModelVertexBuffer(needindex, singleframe);
 }
 
-void PolyModelRenderer::ResetVertexBuffer()
-{
-}
-
 VSMatrix PolyModelRenderer::GetViewToWorldMatrix()
 {
 	Mat4f swapYZ = Mat4f::Null();
diff --git a/src/polyrenderer/scene/poly_model.h b/src/polyrenderer/scene/poly_model.h
index 11e61de7b..4521951e5 100644
--- a/src/polyrenderer/scene/poly_model.h
+++ b/src/polyrenderer/scene/poly_model.h
@@ -41,7 +41,6 @@ public:
 	void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
 	void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) override;
 	IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override;
-	void ResetVertexBuffer() override;
 	VSMatrix GetViewToWorldMatrix() override;
 	void BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
 	void EndDrawHUDModel(AActor *actor) override;
diff --git a/src/r_data/models/models.cpp b/src/r_data/models/models.cpp
index 5b4bf520b..69125991c 100644
--- a/src/r_data/models/models.cpp
+++ b/src/r_data/models/models.cpp
@@ -277,8 +277,6 @@ void FModelRenderer::RenderFrameModels(const FSpriteModelFrame *smf, const FStat
 				mdl->RenderFrame(this, tex, smf->modelframes[i], smfNext->modelframes[i], inter, translation);
 			else
 				mdl->RenderFrame(this, tex, smf->modelframes[i], smf->modelframes[i], 0.f, translation);
-
-			ResetVertexBuffer();
 		}
 	}
 }
diff --git a/src/r_data/models/models.h b/src/r_data/models/models.h
index ba4ed668f..5e72269aa 100644
--- a/src/r_data/models/models.h
+++ b/src/r_data/models/models.h
@@ -70,8 +70,6 @@ public:
 
 	virtual IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) = 0;
 
-	virtual void ResetVertexBuffer() = 0;
-
 	virtual VSMatrix GetViewToWorldMatrix() = 0;
 
 	virtual void BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix, bool mirrored) = 0;
diff --git a/src/swrenderer/things/r_model.cpp b/src/swrenderer/things/r_model.cpp
index 392618708..1f02e0b6c 100644
--- a/src/swrenderer/things/r_model.cpp
+++ b/src/swrenderer/things/r_model.cpp
@@ -218,10 +218,6 @@ namespace swrenderer
 		return new SWModelVertexBuffer(needindex, singleframe);
 	}
 
-	void SWModelRenderer::ResetVertexBuffer()
-	{
-	}
-
 	VSMatrix SWModelRenderer::GetViewToWorldMatrix()
 	{
 		// Calculate the WorldToView matrix as it would have looked like without yshearing:
diff --git a/src/swrenderer/things/r_model.h b/src/swrenderer/things/r_model.h
index 6f83daf76..dc746e8c5 100644
--- a/src/swrenderer/things/r_model.h
+++ b/src/swrenderer/things/r_model.h
@@ -65,7 +65,6 @@ namespace swrenderer
 		void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
 		void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) override;
 		IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override;
-		void ResetVertexBuffer() override;
 		VSMatrix GetViewToWorldMatrix() override;
 		void BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
 		void EndDrawHUDModel(AActor *actor) override;