Advertisement
Danicron

SDLBackend.cpp

Jan 8th, 2020
272
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.60 KB | None | 0 0
  1. /*
  2.  *  SDLBackend.cpp
  3.  *  openc2e
  4.  *
  5.  *  Created by Alyssa Milburn on Sun Oct 24 2004.
  6.  *  Copyright (c) 2004 Alyssa Milburn. All rights reserved.
  7.  *
  8.  *  This library is free software; you can redistribute it and/or
  9.  *  modify it under the terms of the GNU Lesser General Public
  10.  *  License as published by the Free Software Foundation; either
  11.  *  version 2 of the License, or (at your option) any later version.
  12.  *
  13.  *  This library is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  *  Lesser General Public License for more details.
  17.  *
  18.  */
  19.  
  20. #include "SDLBackend.h"
  21. #include "SDL2_gfxPrimitives.h"
  22. #include "SDL_ttf.h"
  23. #include "openc2e.h"
  24. #include "Engine.h"
  25. #include "creaturesImage.h"
  26.  
  27. SDLBackend *g_backend;
  28.  
  29. SDLBackend::SDLBackend() : mainsurface(this) {
  30.     networkingup = false;
  31.     basicfont = 0;
  32.  
  33.     // reasonable defaults
  34.     mainsurface.width = 800;
  35.     mainsurface.height = 600;
  36.     mainsurface.surface = 0;
  37. }
  38.  
  39. int SDLBackend::idealBpp() {
  40.     // shadow surfaces seem to generally be faster (presumably due to overdraw), so get SDL to create one for us
  41.     if (engine.version == 1) return 0;
  42.     else return 16;
  43. }
  44.  
  45. void SDLBackend::resizeNotify(int _w, int _h)
  46. {
  47.     mainsurface.width = _w;
  48.     mainsurface.height = _h;
  49.     mainsurface.surface = SDL_CreateRGBSurface(0, _w, _h, idealBpp(), 0x00FF0000,
  50.         0x0000FF00,
  51.         0x000000FF,
  52.         0xFF000000);
  53.     if (!mainsurface.surface)
  54.         throw creaturesException(std::string("Failed to create SDL surface due to: ") + SDL_GetError());
  55. }
  56.  
  57. void SDLBackend::init() {
  58.     int init = SDL_INIT_VIDEO;
  59.  
  60.     if (SDL_Init(init) < 0)
  61.         throw creaturesException(std::string("SDL error during initialization: ") + SDL_GetError());
  62.  
  63.     std::string windowtitle;
  64.     if (engine.getGameName().size()) windowtitle = engine.getGameName() + " - ";
  65.     windowtitle += "openc2e";
  66.     std::string titlebar = windowtitle + " (development build)";
  67.     SDL_SetWindowTitle(NULL, titlebar.c_str());
  68.  
  69.  
  70.     // TODO SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL) (DEPRECATED);
  71.     SDL_ShowCursor(false);
  72.     if (TTF_Init() == 0) {
  73.         // TODO: think about font sizing
  74.         basicfont = TTF_OpenFont("VeraSe.ttf", 9);
  75.         if (!basicfont) // TODO: think about font fallbacks/etc
  76.         #ifdef __APPLE__
  77.             basicfont = TTF_OpenFont("/Library/Fonts/Arial.ttf", 9);
  78.         #else
  79.             basicfont = TTF_OpenFont("/usr/share/fonts/truetype/ttf-bitstream-vera/VeraSe.ttf", 9);
  80.         #endif
  81.     }
  82. }
  83.  
  84. int SDLBackend::networkInit() {
  85.     if (SDLNet_Init() < 0)
  86.         throw creaturesException(std::string("SDL_net error during initialization: ") + SDLNet_GetError());
  87.     networkingup = true;
  88.  
  89.     listensocket = 0;
  90.     int listenport = 20000;
  91.     while ((!listensocket) && (listenport < 20050)) {
  92.         listenport++;
  93.         IPaddress ip;
  94.  
  95.         SDLNet_ResolveHost(&ip, 0, listenport);
  96.         listensocket = SDLNet_TCP_Open(&ip);
  97.     }
  98.    
  99.     if (!listensocket)
  100.         throw creaturesException(std::string("Failed to open a port to listen on."));
  101.  
  102.     return listenport;
  103. }
  104.  
  105. void SDLBackend::shutdown() {
  106.     if (TTF_WasInit()) {
  107.         if (basicfont) {
  108.             TTF_CloseFont(basicfont);
  109.         }
  110.         TTF_Quit();
  111.     }
  112.     if (networkingup && listensocket)
  113.         SDLNet_TCP_Close(listensocket);
  114.     SDLNet_Quit();
  115.     SDL_Quit();
  116. }
  117.  
  118. void SDLBackend::handleEvents() {
  119.     if (networkingup)
  120.         handleNetworking();
  121. }
  122.  
  123. void SDLBackend::handleNetworking() {
  124.     // handle incoming network connections
  125.     while (TCPsocket connection = SDLNet_TCP_Accept(listensocket)) {
  126.         // check this connection is coming from localhost
  127.         IPaddress *remote_ip = SDLNet_TCP_GetPeerAddress(connection);
  128.         unsigned char *rip = (unsigned char *)&remote_ip->host;
  129.         if ((rip[0] != 127) || (rip[1] != 0) || (rip[2] != 0) || (rip[3] != 1)) {
  130.             std::cout << "Someone tried connecting via non-localhost address! IP: " << (int)rip[0] << "." << (int)rip[1] << "." << (int)rip[2] << "." << (int)rip[3] << std::endl;
  131.             SDLNet_TCP_Close(connection);
  132.             continue;
  133.         }
  134.            
  135.         // read the data from the socket
  136.         std::string data;
  137.         bool done = false;
  138.         while (!done) {
  139.             char buffer;
  140.             int i = SDLNet_TCP_Recv(connection, &buffer, 1);
  141.             if (i == 1) {
  142.                 data = data + buffer;
  143.                 // TODO: maybe we should check for rscr\n like c2e seems to
  144.                 if ((data.size() > 3) && (data.find("rscr\n", data.size() - 5) != data.npos)) done = true;
  145.             } else done = true;
  146.         }
  147.  
  148.         // pass the data onto the engine, and send back our response
  149.         std::string tosend = engine.executeNetwork(data);
  150.         SDLNet_TCP_Send(connection, (void *)tosend.c_str(), tosend.size());
  151.        
  152.         // and finally, close the connection
  153.         SDLNet_TCP_Close(connection);
  154.     }
  155. }
  156.  
  157. bool SDLBackend::pollEvent(SomeEvent &e) {
  158.     SDL_Event event;
  159. retry:
  160.     if (!SDL_PollEvent(&event)) return false;
  161.  
  162.     switch (event.type) {
  163.         case SDL_WINDOWEVENT_RESIZED:
  164.             resizeNotify(event.window.data1, event.window.data2);
  165.             e.type = eventresizewindow;
  166.             e.x = event.window.data1;
  167.             e.y = event.window.data2;
  168.             break;
  169.  
  170.         case SDL_MOUSEMOTION:
  171.             e.type = eventmousemove;
  172.             e.x = event.motion.x;
  173.             e.y = event.motion.y;
  174.             e.xrel = event.motion.xrel;
  175.             e.yrel = event.motion.yrel;
  176.       e.button = 0;
  177.       if (event.motion.state & SDL_BUTTON(1))
  178.         e.button |= buttonleft;
  179.       if (event.motion.state & SDL_BUTTON(2))
  180.         e.button |= buttonmiddle;
  181.       if (event.motion.state & SDL_BUTTON(3))
  182.         e.button |= buttonright;
  183.       if (event.motion.state & SDL_BUTTON(4))
  184.         e.button |= buttonwheelup;
  185.       if (event.motion.state & SDL_BUTTON(5))
  186.         e.button |= buttonwheeldown;
  187.             break;
  188.  
  189.         case SDL_MOUSEBUTTONDOWN:
  190.         case SDL_MOUSEBUTTONUP:
  191.             if (event.type == SDL_MOUSEBUTTONDOWN)
  192.                 e.type = eventmousebuttondown;
  193.             else
  194.                 e.type = eventmousebuttonup;
  195.             switch (event.button.button) {
  196.                 case SDL_BUTTON_LEFT: e.button = buttonleft; break;
  197.                 case SDL_BUTTON_RIGHT: e.button = buttonright; break;
  198.                 case SDL_BUTTON_MIDDLE: e.button = buttonmiddle; break;
  199.                 /*case SDL_MOUSEWHEEL: e.button = buttonwheeldown; break;
  200.                 case SDL_BUTTON_WHEELUP: e.button = buttonwheelup; break;*/
  201.                 default: goto retry;
  202.             }
  203.             e.x = event.button.x;
  204.             e.y = event.button.y;
  205.             break;
  206.  
  207.         case SDL_KEYUP:
  208.             {
  209.                 int key = translateKey(event.key.keysym.sym);
  210.                 if (key != -1) {
  211.                     e.type = eventspecialkeyup;
  212.                     e.key = key;
  213.                     return true;
  214.                 }
  215.                 goto retry;
  216.             }
  217.  
  218.         case SDL_KEYDOWN:
  219.             if ((event.key.keysym <= 0) && ((event.key.keysym >= 32))
  220.             {
  221.                 e.type = eventkeydown;
  222.                 e.key = event.key.keysym & 0x7F;
  223.                 return true;
  224.             } else { // TODO: should this be 'else'?
  225.                 int key = translateKey(event.key.keysym.sym);
  226.                 if (key != -1) {
  227.                     e.type = eventspecialkeydown;
  228.                     e.key = key;
  229.                     return true;
  230.                 }
  231.             }
  232.             goto retry;
  233.             break;
  234.  
  235.         case SDL_QUIT:
  236.             e.type = eventquit;
  237.             break;
  238.  
  239.         default:
  240.             goto retry;
  241.     }
  242.    
  243.     return true;
  244. }
  245.  
  246. void SDLSurface::renderLine(int x1, int y1, int x2, int y2, unsigned int colour) {
  247.     aalineColor(surface, x1, y1, x2, y2, colour);
  248. }
  249.  
  250. SDL_Color getColourFromRGBA(unsigned int c) {
  251.     // SDL's functions seem to want a pixelformat, which is more effort to fake than just doing this
  252.     SDL_Color sdlc;
  253.     sdlc.b = c & 0xff;
  254.     sdlc.g = (c >> 8) & 0xff;
  255.     sdlc.r = (c >> 16) & 0xff;
  256.     assert(c >> 24 == 0);
  257.     sdlc.unused = 0; // T_T "may be used uninitialized in this function"
  258.     return sdlc;
  259. }
  260.  
  261. void SDLSurface::renderText(int x, int y, std::string text, unsigned int colour, unsigned int bgcolour) {
  262.     if (!parent->basicfont) return;
  263.     if (text.empty()) return;
  264.  
  265.     SDL_Color sdlcolour;
  266.     if (engine.version == 1) sdlcolour = palette[colour];
  267.     else sdlcolour = getColourFromRGBA(colour);
  268.    
  269.     SDL_Surface *textsurf;
  270.  
  271.     if (bgcolour == 0) { // transparent
  272.         textsurf = TTF_RenderText_Solid(parent->basicfont, text.c_str(), sdlcolour);
  273.     } else {
  274.         SDL_Color sdlbgcolour;
  275.         if (engine.version == 1) sdlbgcolour = palette[bgcolour];
  276.         else sdlbgcolour = getColourFromRGBA(bgcolour);
  277.         textsurf = TTF_RenderText_Shaded(parent->basicfont, text.c_str(), sdlcolour, sdlbgcolour);
  278.     }
  279.  
  280.     if (!textsurf) return; // thanks, SDL_ttf, we love you too
  281.  
  282.     SDL_Rect destrect;
  283.     destrect.x = x; destrect.y = y;
  284.     SDL_BlitSurface(textsurf, NULL, surface, &destrect);
  285.     SDL_FreeSurface(textsurf);
  286. }
  287.  
  288. //*** code to mirror 16bpp surface - slow, we should cache this!
  289.  
  290. Uint8 *pixelPtr(SDL_Surface *surf, int x, int y, int bytesperpixel) {
  291.     return (Uint8 *)surf->pixels + (y * surf->pitch) + (x * bytesperpixel);
  292. }
  293.  
  294. SDL_Surface *MirrorSurface(SDL_Surface *surf, SDL_Color *surfpalette) {
  295.     SDL_Surface* newsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, surf->format->BitsPerPixel, surf->format->Rmask, surf->format->Gmask, surf->format->Bmask, surf->format->Amask);
  296.     assert(newsurf);
  297.     if (surfpalette) SDL_SetPalette(newsurf, SDL_LOGPAL, surfpalette, 0, 256);
  298.     SDL_BlitSurface(surf, 0, newsurf, 0);
  299.  
  300.     if (SDL_MUSTLOCK(newsurf))
  301.         if (SDL_LockSurface(newsurf) == -1) {
  302.             SDL_FreeSurface(newsurf);
  303.             throw creaturesException("SDLBackend failed to lock surface for mirroring");
  304.         }
  305.  
  306.     for (int y = 0; y < newsurf->h; y++) {
  307.         for (int x = 0; x < (newsurf->w / 2); x++) {
  308.             switch (surf->format->BitsPerPixel) {
  309.                 case 8:
  310.                     {
  311.                     Uint8 *one = pixelPtr(newsurf, x, y, 1);
  312.                     Uint8 *two = pixelPtr(newsurf, (newsurf->w - 1) - x, y, 1);
  313.                     Uint8 temp = *one;
  314.                     *one = *two;
  315.                     *two = temp;
  316.                     }
  317.                     break;
  318.  
  319.                 case 16:
  320.                     {
  321.                     Uint16 *one = (Uint16 *)pixelPtr(newsurf, x, y, 2);
  322.                     Uint16 *two = (Uint16 *)pixelPtr(newsurf, (newsurf->w - 1) - x, y, 2);
  323.                     Uint16 temp = *one;
  324.                     *one = *two;
  325.                     *two = temp;
  326.                     }
  327.                     break;
  328.  
  329.                 case 24:
  330.                     {
  331.                         Uint8 *one = pixelPtr(newsurf, x, y, 3);
  332.                         Uint8 *two = pixelPtr(newsurf, (newsurf->w - 1) - x, y, 3);
  333.                         Uint8 temp[3];
  334.                         temp[0] = *one; temp[1] = *(one + 1); temp[2] = *(one + 2);
  335.                         *one = *two; *(one + 1) = *(two + 1); *(one + 2) = *(two + 2);
  336.                         *two = temp[0]; *(two + 1) = temp[1]; *(two + 2) = temp[2];
  337.                    
  338.                     }
  339.                     break;
  340.  
  341.                 default:
  342.                     if (SDL_MUSTLOCK(newsurf)) SDL_UnlockSurface(newsurf);
  343.                     SDL_FreeSurface(newsurf);
  344.                     throw creaturesException("SDLBackend failed to mirror surface");
  345.             }
  346.         }
  347.     }
  348.    
  349.     if (SDL_MUSTLOCK(newsurf))
  350.         SDL_UnlockSurface(newsurf);
  351.  
  352.     return newsurf;
  353. }
  354.  
  355. //*** end mirror code
  356.  
  357. void SDLSurface::render(shared_ptr<creaturesImage> image, unsigned int frame, int x, int y, bool trans, unsigned char transparency, bool mirror, bool is_background) {
  358.     assert(image);
  359.     assert(image->numframes() > frame);
  360.  
  361.     // don't bother rendering off-screen stuff
  362.     if (x >= (int)width) return; if (y >= (int)height) return;
  363.     if ((x + image->width(frame)) <= 0) return;
  364.     if ((y + image->height(frame)) <= 0) return;
  365.  
  366.     // create surface
  367.     SDL_Surface *surf;
  368.     SDL_Color *surfpalette = 0;
  369.     if (image->format() == if_paletted) {
  370.         surf = SDL_CreateRGBSurfaceFrom(image->data(frame),
  371.                         image->width(frame), image->height(frame),
  372.                         8, // depth
  373.                         image->width(frame), // pitch
  374.                         0, 0, 0, 0);
  375.         assert(surf);
  376.         if (image->hasCustomPalette())
  377.             surfpalette = (SDL_Color *)image->getCustomPalette();
  378.         else
  379.             surfpalette = palette;
  380.         SDL_SetPalette(surf, SDL_LOGPAL, surfpalette, 0, 256);
  381.     } else if (image->format() == if_16bit) {
  382.         unsigned int rmask, gmask, bmask;
  383.         if (image->is565()) {
  384.             rmask = 0xF800; gmask = 0x07E0; bmask = 0x001F;
  385.         } else {
  386.             rmask = 0x7C00; gmask = 0x03E0; bmask = 0x001F;
  387.         }
  388.         surf = SDL_CreateRGBSurfaceFrom(image->data(frame),
  389.                         image->width(frame), image->height(frame),
  390.                         16, // depth
  391.                         image->width(frame) * 2, // pitch
  392.                         rmask, gmask, bmask, 0); // RGBA mask
  393.         assert(surf);
  394.     } else {
  395.         assert(image->format() == if_24bit);
  396.  
  397.         surf = SDL_CreateRGBSurfaceFrom(image->data(frame),
  398.                         image->width(frame), image->height(frame),
  399.                         24, // depth
  400.                         image->width(frame) * 3, // pitch
  401.                         0x00FF0000, 0x0000FF00, 0x000000FF, 0); // RGBA mask
  402.         assert(surf);
  403.  
  404.     }
  405.  
  406.     // try mirroring, if necessary
  407.     try {
  408.         if (mirror) {
  409.             SDL_Surface *newsurf = MirrorSurface(surf, surfpalette);
  410.             SDL_FreeSurface(surf);
  411.             surf = newsurf;
  412.         }
  413.     } catch (std::exception &e) {
  414.         SDL_FreeSurface(surf);
  415.         throw;
  416.     }
  417.    
  418.     // set colour-keying/alpha
  419.     if (!is_background) SDL_SetColorKey(surf, SDL_SRCCOLORKEY, 0);
  420.     if (trans) SDL_SetAlpha(surf, SDL_SRCALPHA, 255 - transparency);
  421.    
  422.     // do actual blit
  423.     SDL_Rect destrect;
  424.     destrect.x = x; destrect.y = y;
  425.     SDL_BlitSurface(surf, 0, surface, &destrect);
  426.  
  427.     // free surface
  428.     SDL_FreeSurface(surf);
  429. }
  430.  
  431. void SDLSurface::renderDone() {
  432.     SDL_Flip(surface);
  433. }
  434.  
  435. void SDLSurface::blitSurface(Surface *s, int x, int y, int w, int h) {
  436.     SDLSurface *src = dynamic_cast<SDLSurface *>(s);
  437.     assert(src);
  438.  
  439.     // TODO: evil use of internal SDL api
  440.     SDL_Rect r; r.x = x; r.y = y; r.w = w; r.h = h;
  441.     SDL_SoftStretch(src->surface, 0, surface, &r);
  442. }
  443.  
  444. Surface *SDLBackend::newSurface(unsigned int w, unsigned int h) {
  445.     SDL_Surface *surf = mainsurface.surface;
  446.     SDL_Surface* underlyingsurf = SDL_CreateRGBSurface(SDL_HWSURFACE, w, h, surf->format->BitsPerPixel, surf->format->Rmask, surf->format->Gmask, surf->format->Bmask, surf->format->Amask);
  447.     assert(underlyingsurf);
  448.     SDLSurface *newsurf = new SDLSurface(this);
  449.     newsurf->surface = underlyingsurf;
  450.     newsurf->width = w;
  451.     newsurf->height = h;
  452.     return newsurf;
  453. }
  454.  
  455. void SDLBackend::freeSurface(Surface *s) {
  456.     SDLSurface *surf = dynamic_cast<SDLSurface *>(s);
  457.     assert(surf);
  458.  
  459.     SDL_FreeSurface(surf->surface);
  460.     delete surf;
  461. }
  462.  
  463. // left out: menu, select, execute, snapshot, numeric keypad, f keys
  464. #define keytrans_size 25
  465. struct _keytrans { int sdl, windows; } keytrans[keytrans_size] = {
  466.     { SDLK_BACKSPACE, 8 },
  467.     { SDLK_TAB, 9 },
  468.     { SDLK_CLEAR, 12 },
  469.     { SDLK_RETURN, 13 },
  470.     { SDLK_RSHIFT, 16 },
  471.     { SDLK_LSHIFT, 16 },
  472.     { SDLK_RCTRL, 17 },
  473.     { SDLK_LCTRL, 17 },
  474.     { SDLK_PAUSE, 19 },
  475.     { SDLK_CAPSLOCK, 20 },
  476.     { SDLK_ESCAPE, 27 },
  477.     { SDLK_SPACE, 32 },
  478.     { SDLK_PAGEUP, 33 },
  479.     { SDLK_PAGEDOWN, 34 },
  480.     { SDLK_END, 35 },
  481.     { SDLK_HOME, 36 },
  482.     { SDLK_LEFT, 37 },
  483.     { SDLK_UP, 38 },
  484.     { SDLK_RIGHT, 39 },
  485.     { SDLK_DOWN, 40 },
  486.     { SDLK_PRINT, 42 },
  487.     { SDLK_INSERT, 45 },
  488.     { SDLK_DELETE, 46 },
  489.     { SDLK_NUMLOCK, 144 }
  490. };
  491.  
  492. // TODO: handle f keys (112-123 under windows, SDLK_F1 = 282 under sdl)
  493.  
  494. // TODO: this is possibly not a great idea, we should maybe maintain our own state table
  495. bool SDLBackend::keyDown(int key) {
  496.     Uint8 *keystate = SDL_GetKeyState(NULL);
  497.    
  498.     for (unsigned int i = 0; i < keytrans_size; i++) {
  499.         if (keytrans[i].windows == key)
  500.             if (keystate[keytrans[i].sdl])
  501.                 return true;
  502.     }
  503.  
  504.     return false;
  505. }
  506.  
  507. int SDLBackend::translateKey(int key) {
  508.     if (key >= 97 && key <= 122) { // lowercase letters
  509.         return key - 32; // capitalise
  510.     }
  511.     if (key >= 48 && key <= 57) { // numbers
  512.         return key;
  513.     }
  514.  
  515.     for (unsigned int i = 0; i < keytrans_size; i++) {
  516.         if (keytrans[i].sdl == key)
  517.             return keytrans[i].windows;
  518.     }
  519.  
  520.     return -1;
  521. }
  522.  
  523. void SDLBackend::setPalette(uint8 *data) {
  524.     // TODO: we only set the palette on our main surface, so will fail for any C1 cameras!
  525.     for (unsigned int i = 0; i < 256; i++) {
  526.         mainsurface.palette[i].r = data[i * 3];
  527.         mainsurface.palette[i].g = data[(i * 3) + 1];
  528.         mainsurface.palette[i].b = data[(i * 3) + 2];
  529.     }
  530. }
  531.  
  532. void SDLBackend::delay(int msec) {
  533.     SDL_Delay(msec);
  534. }
  535.  
  536. unsigned int SDLBackend::textWidth(std::string text) {
  537.     if (!basicfont) return 0;
  538.     if (text.size() == 0) return 0;
  539.  
  540.     int w, h;
  541.  
  542.     if (TTF_SizeText(basicfont, text.c_str(), &w, &h))
  543.         return 0; // error
  544.     else
  545.         return w;
  546. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement