diff --git a/basegraph.cpp b/basegraph.cpp
index e13d9729..ebadb1c9 100644
--- a/basegraph.cpp
+++ b/basegraph.cpp
@@ -265,7 +265,7 @@ void display_data::set_projection(int ed, bool apply_models) {
     eyewidth_translate(ed);
 
     if(dim3) {
-      glhr::projection_multiply(glhr::frustum(current_display->tanfov, current_display->tanfov * vid.yres / vid.xres));
+      glhr::projection_multiply(glhr::frustum(current_display->tanfov, current_display->tanfov * cd->ysize / cd->xsize));
       glhr::projection_multiply(glhr::scale(1, -1, -1));
       current_display->scrdist_text = cd->ysize;
       }
@@ -1254,4 +1254,54 @@ int calcfps() {
   return (1000 * CFPS) / ret;
   }
 
+namespace subscreens {
+
+  vector<display_data> player_displays;
+  bool in;
+  int current_player;
+  
+  bool is_current_player(int id) {
+    if(!in) return true;
+    return id == current_player;
+    }
+
+  void prepare() {
+    int N = multi::players;
+    if(N > 1) {
+      player_displays.resize(N, *current_display);
+      int qrows[10] = {1, 1, 1, 1, 2, 2, 2, 3, 3, 3};
+      int rows = qrows[N];
+      int cols = (N + rows - 1) / rows;
+      for(int i=0; i<N; i++) {
+        auto& pd = player_displays[i];
+        pd.xmin = (i % cols) * 1. / cols;
+        pd.xmax = ((i % cols) + 1.) / cols;
+        pd.ymin = (i / cols) * 1. / rows;
+        pd.ymax = ((i / cols) + 1.) / rows;
+        }
+      }
+    else {
+      player_displays.clear();
+      }
+    }
+
+  bool split(reaction_t what) {
+    using namespace racing;
+    if(in) return false;
+    if(!racing::on && !(shmup::on && DIM == 3)) return false;
+    if(!player_displays.empty()) {
+      in = true;
+      int& p = current_player;
+      for(p = 0; p < multi::players; p++) {
+        dynamicval<display_data*> c(current_display, &player_displays[p]);
+        what();
+        }
+      in = false;
+      return true;
+      }
+    return false;
+    }
+
+  }
+
 }
diff --git a/graph.cpp b/graph.cpp
index d455e378..13c7d2be 100644
--- a/graph.cpp
+++ b/graph.cpp
@@ -6174,15 +6174,22 @@ void drawfullmap() {
 
 void gamescreen(int _darken) {
 
-  if(subscreen_split([=] () {
+  if(subscreens::split([=] () {
     calcparam();
     current_display->set_projection(0, false);
     current_display->set_viewport(0);
     compute_graphical_distance();
     gamescreen(_darken);
     })) {
+    if(racing::on) return;
+    // create the gmatrix
     current_display->set_projection(0, false);
-    current_display->set_viewport(0);    
+    current_display->set_viewport(0);
+    View = subscreens::player_displays[0].view_matrix;
+    viewctr = subscreens::player_displays[0].view_center;
+    just_gmatrix = true;
+    currentmap->draw();
+    just_gmatrix = false;
     return;
     }
 
diff --git a/hyper.h b/hyper.h
index dc2b8e21..4c61982a 100644
--- a/hyper.h
+++ b/hyper.h
@@ -4902,8 +4902,6 @@ namespace racing {
   void displayScore(eLand l);
   }
 
-bool subscreen_split(reaction_t for_each_subscreen);
-
 #else
 
 // static bool on = false: emits a warning
@@ -4925,5 +4923,10 @@ bool no_barriers_in_radius(cell *c, int rad);
 
 extern ld extra_generation_distance;
 
+namespace subscreens {
+  void prepare();
+  bool split(reaction_t for_each_subscreen);
+  }
+
 }
 
diff --git a/hypgraph.cpp b/hypgraph.cpp
index d780c105..583efe22 100644
--- a/hypgraph.cpp
+++ b/hypgraph.cpp
@@ -987,13 +987,16 @@ void spinEdge(ld aspd) {
 
 void centerpc(ld aspd) { 
   
+  if(subscreens::split([=] () {centerpc(aspd);})) return;
+
   #if CAP_CRYSTAL
   if(geometry == gCrystal)
     crystal::centerrug(aspd);
   #endif
 
   if(shmup::on && DIM == 3 && vid.sspeed > -5) {
-    transmatrix at = ggmatrix(shmup::pc[0]->base) * shmup::pc[0]->at * cpush(2, -vid.yshift);  
+    int id = subscreens::in ? subscreens::current_player : 0;
+    transmatrix at = ggmatrix(shmup::pc[id]->base) * shmup::pc[id]->at * cpush(2, -vid.yshift);  
     View = inverse(at) * View;
     #if CAP_RACING
     if(racing::on) racing::set_view();
@@ -1057,7 +1060,7 @@ void centerpc(ld aspd) {
 
 void optimizeview() {
 
-  subscreen_split(optimizeview);
+  if(subscreens::split(optimizeview)) return;
   
   #if CAP_ANIMATIONS
   if(centerover.at && inmirror(centerover.at)) {
diff --git a/racing.cpp b/racing.cpp
index d2bff9bf..dcc04a18 100644
--- a/racing.cpp
+++ b/racing.cpp
@@ -643,22 +643,20 @@ bool inrec = false;
 
 ld race_angle = 90;
 
-int current_player;
-
 void set_view() {
 
+  multi::cpid = subscreens::in ? subscreens::current_player : 0;
+
   if(race_start_tick == 0) race_start_tick = ticks + 5000;
 
-  if(subscreen_split(set_view)) return;
-
-  shmup::monster *who = shmup::pc[current_player];
+  shmup::monster *who = shmup::pc[multi::cpid];
   
   if(!inrec) {
     const transmatrix T = who->at;
     ld alpha = -atan2(T * C0);
     ld distance = hdist0(T * C0);
     ld beta = -atan2(xpush(-distance) * spin(-alpha) * T * Cx1);
-    current_history[current_player].emplace_back(ghostmoment{ticks - race_start_tick, rti_id[who->base], 
+    current_history[multi::cpid].emplace_back(ghostmoment{ticks - race_start_tick, rti_id[who->base], 
       angle_to_uchar(alpha),
       frac_to_uchar(distance / distance_multiplier),
       angle_to_uchar(beta),
@@ -1092,29 +1090,6 @@ auto hooks1 =
     else return named_functionality();
     });
 
-vector<display_data> player_displays;
-bool in_subscreen;
-
-void prepare_subscreens() {
-  int N = multi::players;
-  if(N > 1) {
-    player_displays.resize(N, *current_display);
-    int qrows[10] = {1, 1, 1, 1, 2, 2, 2, 3, 3, 3};
-    int rows = qrows[N];
-    int cols = (N + rows - 1) / rows;
-    for(int i=0; i<N; i++) {
-      auto& pd = player_displays[i];
-      pd.xmin = (i % cols) * 1. / cols;
-      pd.xmax = ((i % cols) + 1.) / cols;
-      pd.ymin = (i / cols) * 1. / rows;
-      pd.ymax = ((i / cols) + 1.) / rows;
-      }
-    }
-  else {
-    player_displays.clear();
-    }
-  }
-
 map<string, map<eLand, int> > scoreboard;
 
 void uploadScore() {
@@ -1153,7 +1128,7 @@ void displayScore(eLand l) {
   }
 
 void race_won() {
-  if(!race_finish_tick[current_player]) {
+  if(!race_finish_tick[multi::cpid]) {
     int result = ticks - race_start_tick;
     int losers = 0;
     int place = 1;
@@ -1161,9 +1136,9 @@ void race_won() {
     for(auto& ghost: ghostset()[specialland]) if(ghost.result < result) place++; else losers++;
     for(auto& ghost: oghostset()[specialland]) if(ghost.result < result) place++; else losers++;
 
-    if(place == 1 && losers) trophy[current_player] = 0xFFD500FF;
-    if(place == 2) trophy[current_player] = 0xFFFFC0FF;
-    if(place == 3) trophy[current_player] = 0x967444FF;
+    if(place == 1 && losers) trophy[multi::cpid] = 0xFFD500FF;
+    if(place == 2) trophy[multi::cpid] = 0xFFFFC0FF;
+    if(place == 3) trophy[multi::cpid] = 0x967444FF;
   
     if(place + losers > 1)
       addMessage(XLAT("Finished the race! Time: %1, place: %2 out of %3", racetimeformat(result), its(place), its(place+losers)));
@@ -1173,7 +1148,7 @@ void race_won() {
     if(place == 1 && losers && official_race)
       achievement_gain("RACEWON", rg::racing);
     
-    race_finish_tick[current_player] = ticks;
+    race_finish_tick[multi::cpid] = ticks;
     charstyle gcs = getcs();
     for(color_t *x: {&gcs.skincolor, &gcs.haircolor, &gcs.dresscolor, &gcs.swordcolor, &gcs.dresscolor2}) {
       for(int a=1; a<4; a++)
@@ -1196,7 +1171,7 @@ void race_won() {
       }
     subtrack.resize(ngh);    
 
-    subtrack.emplace_back(ghost{gcs, result, race_checksum, time(NULL), current_history[current_player]});
+    subtrack.emplace_back(ghost{gcs, result, race_checksum, time(NULL), current_history[multi::cpid]});
     sort(subtrack.begin(), subtrack.end(), [] (const ghost &g1, const ghost &g2) { return g1.result < g2.result; });
     if(isize(subtrack) > ghosts_to_save && ghosts_to_save > 0) 
       subtrack.resize(ghosts_to_save);
@@ -1340,21 +1315,4 @@ void add_debug(cell *c) {
 
 }
 
-bool subscreen_split(reaction_t what) {
-  using namespace racing;
-  if(!racing::on) return false;
-  if(in_subscreen) return false;
-  if(!player_displays.empty()) {
-    in_subscreen = true;
-    int& p = current_player;
-    for(p = 0; p < multi::players; p++) {
-      dynamicval<display_data*> c(current_display, &player_displays[p]);
-      what();
-      }
-    in_subscreen = false;
-    return true;
-    }
-  return false;
-  }
-
 }
diff --git a/shmup.cpp b/shmup.cpp
index a5d5a5b8..9c0f055f 100644
--- a/shmup.cpp
+++ b/shmup.cpp
@@ -1582,7 +1582,7 @@ void movePlayer(monster *m, int delta) {
   cpid = m->pid;
 
   #if CAP_RACING
-  if(racing::on && cpid != racing::current_player) return;
+  if(racing::on && cpid != subscreens::current_player) return;
   #endif
   
   double mturn = 0, mgo = 0, mdx = 0, mdy = 0;
@@ -1753,7 +1753,7 @@ void movePlayer(monster *m, int delta) {
     playerturn[cpid] = mgo * SCALE * delta / 200;
     playerturny[cpid] = mturn * SCALE * delta / 200;
 
-    if(!lctrlclick) {
+    if(!lctrlclick && cpid == 0) {
       playerturn[cpid] += mouseaim_x;
       playerturny[cpid] += mouseaim_y;
       mouseaim_x = mouseaim_y = 0;
@@ -3112,7 +3112,7 @@ hookset<bool(int)> *hooks_turn;
 
 void turn(int delta) {
 
-  if(subscreen_split( [delta] () { turn(delta); })) return;
+  if(racing::on && subscreens::split( [delta] () { turn(delta); })) return;
 
   if(callhandlers(false, hooks_turn, delta)) return;
   if(!shmup::on) return;
@@ -3463,16 +3463,16 @@ bool drawMonster(const transmatrix& V, cell *c, const transmatrix*& Vboat, trans
     switch(m->type) {
       case moPlayer: 
         playerfound = true;
-        cpid = m->pid; 
 
-        if(!hide_player()) {
+        if(!hide_player() || !subscreens::is_current_player(m->pid)) {
+          dynamicval<int> d(cpid, m->pid);
           if(DIM == 3) view = view * spin(-M_PI/2);
           drawPlayerEffects(view, c, true);
           if(m->inBoat) m->footphase = 0;
           if(mapeditor::drawplayer) drawMonsterType(moPlayer, c, view, 0xFFFFFFC0, m->footphase);
           }
 
-        if(keyresult[cpid]) {
+        if(subscreens::is_current_player(m->pid) && keyresult[cpid]) {
           hyperpoint h = keytarget(cpid);
           if(DIM == 2) 
             queuechr(h, vid.fsize, '+', iinf[keyresult[cpid]].color);
diff --git a/system.cpp b/system.cpp
index 43f63f3e..e0d2232c 100644
--- a/system.cpp
+++ b/system.cpp
@@ -1366,9 +1366,7 @@ void start_game() {
 #if CAP_TEXTURE
   texture::config.remap();
 #endif
-#if CAP_RACING
-  racing::prepare_subscreens();
-#endif
+  subscreens::prepare();
   }
 
 void restart_game(char switchWhat) {