diff --git a/src/doomdef.h b/src/doomdef.h
index 3649db08ea7b170086e6235bf4ac7d0d95c9567d..d4ad4a68a85e17cc0de7493d9d7f970a049462be 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -469,7 +469,7 @@ extern const char *compdate, *comptime, *comprevision;
 
 #if !defined (_NDS) && !defined (_PSP)
 ///	Shuffle's incomplete OpenGL sorting code.
-//#define SHUFFLE
+#define SHUFFLE // This has nothing to do with sorting, why was it disabled?
 #endif
 
 #if !defined (_NDS) && !defined (_PSP)
diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c
index 6dc0f0f790d36e58448f1d543908d7ba3dc19706..43d4537fd3d10d4d1c598611fd99351c7dc93f18 100644
--- a/src/hardware/hw_draw.c
+++ b/src/hardware/hw_draw.c
@@ -209,6 +209,76 @@ void HWR_DrawSciencePatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, INT32 option,
 		HWD.pfnDrawPolygon(NULL, v, 4, flags);
 }
 
+void HWR_DrawCroppedPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option, fixed_t scale, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h)
+{
+	FOutVector v[4];
+	FBITFIELD flags;
+
+	float cx = FIXED_TO_FLOAT(x);
+	float cy = FIXED_TO_FLOAT(y);
+
+//  3--2
+//  | /|
+//  |/ |
+//  0--1
+	float sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f;
+	float sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f;
+	float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(scale);
+	float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(scale);
+
+	// make patch ready in hardware cache
+	HWR_GetPatch(gpatch);
+
+	switch (option & V_SCALEPATCHMASK)
+	{
+	case V_NOSCALEPATCH:
+		pdupx = pdupy = 2.0f;
+		break;
+	case V_SMALLSCALEPATCH:
+		pdupx = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupx);
+		pdupy = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupy);
+		break;
+	case V_MEDSCALEPATCH:
+		pdupx = 2.0f * FIXED_TO_FLOAT(vid.fmeddupx);
+		pdupy = 2.0f * FIXED_TO_FLOAT(vid.fmeddupy);
+		break;
+	}
+
+	if (option & V_NOSCALESTART)
+		sdupx = sdupy = 2.0f;
+
+	v[0].x = v[3].x = (cx*sdupx-gpatch->leftoffset*pdupx)/vid.width - 1;
+	v[2].x = v[1].x = ((cx-sx)*sdupx+(w-gpatch->leftoffset)*pdupx)/vid.width - 1;
+	v[0].y = v[1].y = 1-(cy*sdupy-gpatch->topoffset*pdupy)/vid.height;
+	v[2].y = v[3].y = 1-((cy-sy)*sdupy+(h-gpatch->topoffset)*pdupy)/vid.height;
+
+	v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
+
+	v[0].sow = v[3].sow = ((float)sx/(float)gpatch->height);
+	v[2].sow = v[1].sow = gpatch->max_s*((float)w/(float)gpatch->width);
+	v[0].tow = v[1].tow = ((float)sy/(float)gpatch->height);
+	v[2].tow = v[3].tow = gpatch->max_t*((float)h/(float)gpatch->height);
+
+	flags = BLENDMODE|PF_Clip|PF_NoZClip|PF_NoDepthTest;
+
+	if (option & V_WRAPX)
+		flags |= PF_ForceWrapX;
+	if (option & V_WRAPY)
+		flags |= PF_ForceWrapY;
+
+	// clip it since it is used for bunny scroll in doom I
+	if (option & V_TRANSLUCENT)
+	{
+		FSurfaceInfo Surf;
+		Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff;
+		Surf.FlatColor.s.alpha = (UINT8)cv_grtranslucenthud.value;
+		flags |= PF_Modulated;
+		HWD.pfnDrawPolygon(&Surf, v, 4, flags);
+	}
+	else
+		HWD.pfnDrawPolygon(NULL, v, 4, flags);
+}
+
 void HWR_DrawClippedPatch (GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option)
 {
 	// hardware clips the patch quite nicely anyway :)
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index b2b5177372a387bd622121d682e072cd78c31143..14b1556188625c5c53baad602e2208f398826e4d 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -1212,23 +1212,17 @@ static void HWR_SplitFog(sector_t *sector, wallVert3D *wallVerts, FSurfaceInfo*
 
 		if (list[i].caster)
 		{
-			if (sector->lightlist[i].caster->flags & FF_SOLID && !(cutflag & FF_EXTRA))
-				solid = true;
-			else if (sector->lightlist[i].caster->flags & FF_CUTEXTRA && cutflag & FF_EXTRA)
+			if (sector->lightlist[i].caster->flags & FF_FOG && cutflag & FF_FOG) // Only fog cuts fog
 			{
 				if (sector->lightlist[i].caster->flags & FF_EXTRA)
 				{
-					if (sector->lightlist[i].caster->flags == cutflag)
+					if (sector->lightlist[i].caster->flags == cutflag) // only cut by the same
 						solid = true;
 				}
 				else
 					solid = true;
 			}
-			else
-				solid = false;
 		}
-		else
-			solid = false;
 
 		height = FIXED_TO_FLOAT(list[i].height);
 
@@ -1645,7 +1639,12 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 				blendmode = PF_Environment;
 
 			if (gr_frontsector->numlights)
-				HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTSOLIDS);
+			{
+				if (!(blendmode & PF_Masked))
+					HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTSOLIDS|FF_TRANSLUCENT);
+				else
+					HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTSOLIDS);
+			}
 			else if (!(blendmode & PF_Masked))
 				HWR_AddTransparentWall(wallVerts, &Surf, gr_midtexture, blendmode, false, lightnum, colormap);
 			else
@@ -3385,30 +3384,17 @@ noshadow:
 
 		if (sector->numlights)
 		{
-			INT32 light = R_GetPlaneLight(sector, spr->mobj->z, false);
-
-			if ((sector->lightlist[light].height > (spr->mobj->z + spr->mobj->height)) && !(sector->lightlist[light].flags & FF_NOSHADE))
-			{
-				if (!(spr->mobj->frame & FF_FULLBRIGHT))
-					lightlevel = LightLevelToLum(*sector->lightlist[light].lightlevel);
-				else
-					lightlevel = LightLevelToLum(255);
+			INT32 light;
 
-				if (sector->lightlist[light].extra_colormap)
-					colormap = sector->lightlist[light].extra_colormap;
-			}
-			else // If we can't use the light at its bottom, we'll use the light at its top
-			{
-				light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false);
+			light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
 
-				if (!(spr->mobj->frame & FF_FULLBRIGHT))
-					lightlevel = LightLevelToLum(*sector->lightlist[light].lightlevel);
-				else
-					lightlevel = LightLevelToLum(255);
+			if (!(spr->mobj->frame & FF_FULLBRIGHT))
+				lightlevel = LightLevelToLum(*sector->lightlist[light].lightlevel);
+			else
+				lightlevel = LightLevelToLum(255);
 
-				if (sector->lightlist[light].extra_colormap)
-					colormap = sector->lightlist[light].extra_colormap;
-			}
+			if (sector->lightlist[light].extra_colormap)
+				colormap = sector->lightlist[light].extra_colormap;
 		}
 		else
 		{
@@ -3855,7 +3841,7 @@ static void HWR_DrawSprites(void)
 				HWR_DrawPrecipitationSprite(spr);
 			else
 #endif
-				if (spr->mobj->skin)
+				if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
 				{
 					if (!cv_grmd2.value || (cv_grmd2.value && md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound == true))
 						HWR_DrawSprite(spr);
@@ -3884,7 +3870,7 @@ static void HWR_DrawMD2S(void)
 			if (!spr->precip)
 			{
 #endif
-				if (spr->mobj && spr->mobj->skin)
+				if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
 				{
 					if ((md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound == false) && (md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale > 0.0f))
 						HWR_DrawMD2(spr);
@@ -4323,6 +4309,8 @@ static void HWR_DrawSkyBackground(player_t *player)
 
 	v[0].z = v[1].z = v[2].z = v[3].z = 4.0f;
 
+	// X
+
 	if (textures[skytexture]->width > 256)
 		angle = (angle_t)((float)(dup_viewangle + gr_xtoviewangle[0])
 						/((float)textures[skytexture]->width/256.0f))
@@ -4337,9 +4325,19 @@ static void HWR_DrawSkyBackground(player_t *player)
 	v[0].sow = v[3].sow = 0.22f+(f)/(textures[skytexture]->width/2);
 	v[2].sow = v[1].sow = 0.22f+(f+(127))/(textures[skytexture]->width/2);
 
+
+	// Y
+
+	if (textures[skytexture]->height > 256)
+		angle = (angle_t)((float)(aimingangle)
+						*(256.0f/(float)textures[skytexture]->height))
+							%(ANGLE_90-1); // Just so that looking up and down scales right
+	else
+		angle = (aimingangle);
+
 	f = (float)((textures[skytexture]->height/2)
 	            * FIXED_TO_FLOAT(FINETANGENT((2048
-	 - ((INT32)aimingangle>>(ANGLETOFINESHIFT + 1))) & FINEMASK)));
+	 - ((INT32)angle>>(ANGLETOFINESHIFT + 1))) & FINEMASK)));
 
 	v[3].tow = v[2].tow = 0.22f+(f)/(textures[skytexture]->height/2);
 	v[0].tow = v[1].tow = 0.22f+(f+(127))/(textures[skytexture]->height/2);
@@ -4405,6 +4403,205 @@ void HWR_SetViewSize(void)
 	gr_pspriteyscale = ((vid.height*gr_pspritexscale*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width;
 }
 
+// ==========================================================================
+// Same as rendering the player view, but from the skybox object
+// ==========================================================================
+void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
+{
+	const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd);
+	FTransform stransform;
+
+	{
+		// do we really need to save player (is it not the same)?
+		player_t *saved_player = stplyr;
+		stplyr = player;
+		ST_doPaletteStuff();
+		stplyr = saved_player;
+#ifdef ALAM_LIGHTING
+		HWR_SetLights(viewnumber);
+#endif
+	}
+
+	// note: sets viewangle, viewx, viewy, viewz
+	R_SkyboxFrame(player);
+
+	// copy view cam position for local use
+	dup_viewx = viewx;
+	dup_viewy = viewy;
+	dup_viewz = viewz;
+	dup_viewangle = viewangle;
+
+	// set window position
+	gr_centery = gr_basecentery;
+	gr_viewwindowy = gr_baseviewwindowy;
+	gr_windowcentery = gr_basewindowcentery;
+	if (splitscreen && viewnumber == 1)
+	{
+		gr_viewwindowy += (vid.height/2);
+		gr_windowcentery += (vid.height/2);
+	}
+
+	// check for new console commands.
+	NetUpdate();
+
+	gr_viewx = FIXED_TO_FLOAT(dup_viewx);
+	gr_viewy = FIXED_TO_FLOAT(dup_viewy);
+	gr_viewz = FIXED_TO_FLOAT(dup_viewz);
+	gr_viewsin = FIXED_TO_FLOAT(viewsin);
+	gr_viewcos = FIXED_TO_FLOAT(viewcos);
+
+	gr_viewludsin = FIXED_TO_FLOAT(FINECOSINE(aimingangle>>ANGLETOFINESHIFT));
+	gr_viewludcos = FIXED_TO_FLOAT(-FINESINE(aimingangle>>ANGLETOFINESHIFT));
+
+	//04/01/2000: Hurdler: added for T&L
+	//                     It should replace all other gr_viewxxx when finished
+	atransform.anglex = (float)(aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
+	atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
+	atransform.x      = gr_viewx;  // FIXED_TO_FLOAT(viewx)
+	atransform.y      = gr_viewy;  // FIXED_TO_FLOAT(viewy)
+	atransform.z      = gr_viewz;  // FIXED_TO_FLOAT(viewz)
+	atransform.scalex = 1;
+	atransform.scaley = ORIGINAL_ASPECT;
+	atransform.scalez = 1;
+	atransform.fovxangle = fpov; // Tails
+	atransform.fovyangle = fpov; // Tails
+	atransform.splitscreen = splitscreen;
+
+	// Transform for sprites
+	stransform.anglex = 0.0f;
+	stransform.angley = -270.0f;
+	stransform.x      = 0.0f;
+	stransform.y      = 0.0f;
+	stransform.z      = 0.0f;
+	stransform.scalex = 1;
+	stransform.scaley = 1;
+	stransform.scalez = 1;
+	stransform.fovxangle = 90.0f;
+	stransform.fovyangle = 90.0f;
+	stransform.splitscreen = splitscreen;
+
+	gr_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));
+
+	//------------------------------------------------------------------------
+	HWR_ClearView();
+
+if (0)
+{ // I don't think this is ever used.
+	if (cv_grfog.value)
+		HWR_FoggingOn(); // First of all, turn it on, set the default user settings too
+	else
+		HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 0); // Turn it off
+}
+
+#ifndef _NDS
+	if (drawsky)
+		HWR_DrawSkyBackground(player);
+#else
+	(void)HWR_DrawSkyBackground;
+#endif
+
+	//Hurdler: it doesn't work in splitscreen mode
+	drawsky = splitscreen;
+
+	HWR_ClearSprites();
+
+#ifdef SORTING
+	drawcount = 0;
+#endif
+	HWR_ClearClipSegs();
+
+	//04/01/2000: Hurdler: added for T&L
+	//                     Actually it only works on Walls and Planes
+	HWD.pfnSetTransform(&atransform);
+
+	validcount++;
+
+	HWR_RenderBSPNode((INT32)numnodes-1);
+
+	// Make a viewangle int so we can render things based on mouselook
+	if (player == &players[consoleplayer])
+		viewangle = localaiming;
+	else if (splitscreen && player == &players[secondarydisplayplayer])
+		viewangle = localaiming2;
+
+	// Handle stuff when you are looking farther up or down.
+	if ((aimingangle || cv_grfov.value+player->fovadd > 90*FRACUNIT))
+	{
+		dup_viewangle += ANGLE_90;
+		HWR_ClearClipSegs();
+		HWR_RenderBSPNode((INT32)numnodes-1); //left
+
+		dup_viewangle += ANGLE_90;
+		if (((INT32)aimingangle > ANGLE_45 || (INT32)aimingangle<-ANGLE_45))
+		{
+			HWR_ClearClipSegs();
+			HWR_RenderBSPNode((INT32)numnodes-1); //back
+		}
+
+		dup_viewangle += ANGLE_90;
+		HWR_ClearClipSegs();
+		HWR_RenderBSPNode((INT32)numnodes-1); //right
+
+		dup_viewangle += ANGLE_90;
+	}
+
+	// Check for new console commands.
+	NetUpdate();
+
+#ifdef ALAM_LIGHTING
+	//14/11/99: Hurdler: moved here because it doesn't work with
+	// subsector, see other comments;
+	HWR_ResetLights();
+#endif
+
+	// Draw MD2 and sprites
+#ifdef SORTING
+	HWR_SortVisSprites();
+#endif
+	HWR_DrawMD2S();
+
+	// Draw the sprites with trivial transform
+	HWD.pfnSetTransform(&stransform);
+#ifdef SORTING
+	HWR_DrawSprites();
+#endif
+#ifdef NEWCORONAS
+	//Hurdler: they must be drawn before translucent planes, what about gl fog?
+	HWR_DrawCoronas();
+#endif
+
+#ifdef SORTING
+	if (numplanes || numwalls) //Hurdler: render 3D water and transparent walls after everything
+	{
+		HWR_CreateDrawNodes();
+	}
+#else
+	if (numfloors || numwalls)
+	{
+		HWD.pfnSetTransform(&atransform);
+		if (numfloors)
+			HWR_Render3DWater();
+		if (numwalls)
+			HWR_RenderTransparentWalls();
+	}
+#endif
+
+	HWD.pfnSetTransform(NULL);
+
+	// put it off for menus etc
+	if (cv_grfog.value)
+		HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 0);
+
+	HWR_DoPostProcessor(player);
+
+	// Check for new console commands.
+	NetUpdate();
+
+	// added by Hurdler for correct splitscreen
+	// moved here by hurdler so it works with the new near clipping plane
+	HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE);
+}
+
 // ==========================================================================
 //
 // ==========================================================================
@@ -4413,6 +4610,11 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
 	const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd);
 	FTransform stransform;
 
+	const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on
+
+	if (skybox && drawsky) // If there's a skybox and we should be drawing the sky, draw the skybox
+		HWR_RenderSkyboxView(viewnumber, player); // This is drawn before everything else so it is placed behind
+
 	{
 		// do we really need to save player (is it not the same)?
 		player_t *saved_player = stplyr;
@@ -4425,7 +4627,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
 	}
 
 	// note: sets viewangle, viewx, viewy, viewz
-	R_SetupFrame(player, false);
+	R_SetupFrame(player, false); // This can stay false because it is only used to set viewsky in r_main.c, which isn't used here
 
 	// copy view cam position for local use
 	dup_viewx = viewx;
@@ -4496,7 +4698,7 @@ if (0)
 }
 
 #ifndef _NDS
-	if (drawsky)
+	if (!skybox && drawsky) // Don't draw the regular sky if there's a skybox
 		HWR_DrawSkyBackground(player);
 #else
 	(void)HWR_DrawSkyBackground;
diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h
index d3b3df6677badb362eef70d83bf366662b4d816f..a6cf3fb7f153ba1188afb48380717b129ea7a1fc 100644
--- a/src/hardware/hw_main.h
+++ b/src/hardware/hw_main.h
@@ -35,6 +35,7 @@ void HWR_clearAutomap(void);
 void HWR_drawAMline(const fline_t *fl, INT32 color);
 void HWR_FadeScreenMenuBack(UINT32 color, INT32 height);
 void HWR_DrawConsoleBack(UINT32 color, INT32 height);
+void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player);
 void HWR_RenderPlayerView(INT32 viewnumber, player_t *player);
 void HWR_DrawViewBorder(INT32 clearlines);
 void HWR_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum);
@@ -45,6 +46,7 @@ void HWR_SetViewSize(void);
 void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option);
 void HWR_DrawClippedPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option);
 void HWR_DrawSciencePatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, INT32 option, fixed_t scale);
+void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, INT32 option, fixed_t scale, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h);
 void HWR_DrawTranslucentPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option);
 void HWR_DrawSmallPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option, const UINT8 *colormap);
 void HWR_DrawMappedPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option, const UINT8 *colormap);
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index fb012535c9a3a31a6a4acaf0648d500661224310..79f7c905ea7272e82bbf01f174a159e9a3c45878 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -1087,30 +1087,17 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 
 		if (sector->numlights)
 		{
-			INT32 light = R_GetPlaneLight(sector, spr->mobj->z, false);
+			INT32 light;
 
-			if (sector->lightlist[light].height > (spr->mobj->z + spr->mobj->height))
-			{
-				if (!(spr->mobj->frame & FF_FULLBRIGHT))
-					lightlevel = LightLevelToLum(*sector->lightlist[light].lightlevel);
-				else
-					lightlevel = LightLevelToLum(255);
-
-				if (sector->lightlist[light].extra_colormap)
-					colormap = sector->lightlist[light].extra_colormap;
-			}
-			else // If we can't use the light at its bottom, we'll use the light at its top
-			{
-				light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false);
+			light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
 
-				if (!(spr->mobj->frame & FF_FULLBRIGHT))
-					lightlevel = LightLevelToLum(*sector->lightlist[light].lightlevel);
-				else
-					lightlevel = LightLevelToLum(255);
+			if (!(spr->mobj->frame & FF_FULLBRIGHT))
+				lightlevel = LightLevelToLum(*sector->lightlist[light].lightlevel);
+			else
+				lightlevel = LightLevelToLum(255);
 
-				if (sector->lightlist[light].extra_colormap)
-					colormap = sector->lightlist[light].extra_colormap;
-			}
+			if (sector->lightlist[light].extra_colormap)
+				colormap = sector->lightlist[light].extra_colormap;
 		}
 		else
 		{
@@ -1156,7 +1143,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 		else
 		{
 			Surf.FlatColor.s.alpha = 0xFF;
-			blend = PF_Translucent;
+			blend = PF_Translucent|PF_Occlude;
 		}
 
 		// dont forget to enabled the depth test because we can't do this like
@@ -1164,7 +1151,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 
 		// 1. load model+texture if not already loaded
 		// 2. draw model with correct position, rotation,...
-		if (spr->mobj->skin)
+		if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) // Use the player MD2 list if the mobj has a skin and is using the player sprites
 		{
 			md2 = &md2_playermodels[(skin_t*)spr->mobj->skin-skins];
 			md2->skin = (skin_t*)spr->mobj->skin-skins;
@@ -1188,13 +1175,14 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 				return;
 			}
 		}
-		HWD.pfnSetBlend(blend);
+		//HWD.pfnSetBlend(blend); // This seems to actually break translucency?
 		finalscale = md2->scale;
 		//Hurdler: arf, I don't like that implementation at all... too much crappy
 		gpatch = md2->grpatch;
 		if (!gpatch || !gpatch->mipmap.grInfo.format || !gpatch->mipmap.downloaded)
 			md2_loadTexture(md2);
-		else if (gpatch->mipmap.grInfo.format)
+
+		if (gpatch && gpatch->mipmap.grInfo.format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture
 		{
 			// This is safe, since we know the texture has been downloaded
 			HWD.pfnSetTexture(&gpatch->mipmap);
@@ -1211,7 +1199,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 		buff = md2->model->glCommandBuffer;
 		curr = &md2->model->frames[frame];
 		if (cv_grmd2.value == 1
-		    && spr->mobj->state->nextstate != S_NULL
+		    && spr->mobj->state->nextstate != S_NULL && states[spr->mobj->state->nextstate].sprite != SPR_NULL
 		    && !(spr->mobj->player && (spr->mobj->state->nextstate == S_PLAY_TAP1 || spr->mobj->state->nextstate == S_PLAY_TAP2) && spr->mobj->state == &states[S_PLAY_STND]))
 		{
 			const INT32 nextframe = (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) % md2->model->header.numFrames;
diff --git a/src/r_main.c b/src/r_main.c
index 10228c29a4684c38175d4b0a42d6b27337e46a1b..c55de3940c9ee93945cbd2dba9272866b8051ae8 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -732,7 +732,7 @@ static mobj_t *viewmobj;
 // WARNING: a should be unsigned but to add with 2048, it isn't!
 #define AIMINGTODY(a) ((FINETANGENT((2048+(((INT32)a)>>ANGLETOFINESHIFT)) & FINEMASK)*160)>>FRACBITS)
 
-static void R_SkyboxFrame(player_t *player)
+void R_SkyboxFrame(player_t *player)
 {
 	INT32 dy = 0;
 	camera_t *thiscam;
diff --git a/src/r_main.h b/src/r_main.h
index a6387bbc237dfb88879db584c920306b75495c70..8a39b7d30e33c9c432a001d6fa49c176829eca17 100644
--- a/src/r_main.h
+++ b/src/r_main.h
@@ -101,6 +101,8 @@ void R_SetViewSize(void);
 // do it (sometimes explicitly called)
 void R_ExecuteSetViewSize(void);
 
+void R_SkyboxFrame(player_t *player);
+
 void R_SetupFrame(player_t *player, boolean skybox);
 // Called by G_Drawer.
 void R_RenderPlayerView(player_t *player);
diff --git a/src/screen.c b/src/screen.c
index 666f2e1e2aa1b6a7444023682cb363506f79f16b..0850560655b9c53e224f4a2134021c9f2a4582e4 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -227,7 +227,11 @@ void SCR_Startup(void)
 	vid.dupx = vid.dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
 	vid.fdupx = FixedDiv(vid.width*FRACUNIT, BASEVIDWIDTH*FRACUNIT);
 	vid.fdupy = FixedDiv(vid.height*FRACUNIT, BASEVIDHEIGHT*FRACUNIT);
-	vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy);
+
+#ifdef HWRENDER
+	if (rendermode != render_opengl && rendermode != render_none) // This was just placing it incorrectly at non aspect correct resolutions, not sure if it does anything in software
+#endif
+		vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy);
 
 	vid.meddupx = (UINT8)(vid.dupx >> 1) + 1;
 	vid.meddupy = (UINT8)(vid.dupy >> 1) + 1;
@@ -269,7 +273,12 @@ void SCR_Recalc(void)
 	vid.dupx = vid.dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
 	vid.fdupx = FixedDiv(vid.width*FRACUNIT, BASEVIDWIDTH*FRACUNIT);
 	vid.fdupy = FixedDiv(vid.height*FRACUNIT, BASEVIDHEIGHT*FRACUNIT);
-	vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy);
+
+#ifdef HWRENDER
+	if (rendermode != render_opengl && rendermode != render_none) // This was just placing it incorrectly at non aspect correct resolutions, not sure if it does anything in software
+#endif
+		vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy);
+
 	//vid.baseratio = FixedDiv(vid.height << FRACBITS, BASEVIDHEIGHT << FRACBITS);
 	vid.baseratio = FRACUNIT;
 
diff --git a/src/v_video.c b/src/v_video.c
index 17cd4362906062c2a9c2bc7f204979d6d3c69081..76728a35dbe02edda457586fb70a4e9070fc7c98 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -1040,9 +1040,12 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, INT32 scrn, patch_t *patch, fixed_
 	const UINT8 *source, *deststop;
 
 #ifdef HWRENDER
-	// fuck off
+	// Done
 	if (rendermode != render_soft && rendermode != render_none)
+	{
+		HWR_DrawCroppedPatch((GLPatch_t *)patch, x, y, scrn, science, sx, sy, w, h);
 		return;
+	}
 #endif
 
 	// only use one dup, to avoid stretching (har har)