#include"window.hpp" #include"SDL.h" #include"SDL_ttf.h" #include<iostream> #include<vector> #include<cstdlib> #include<ctime> namespace game { // render object implementation for SDL2 struct SDL_RenderObject : public RenderObject { SDL_Window *window = NULL; SDL_Renderer *ren = NULL; std::vector<SDL_Surface *> surfaces; std::vector<SDL_Texture *> textures; std::vector<TTF_Font *> fonts; std::vector<SDL_Joystick *> joysticks; SDL_Texture *tex = NULL; SDL_Surface *surface = NULL; int width = 0, height = 0; // destructor on clean up ~SDL_RenderObject() { release_images(); release_joysticks(); std::cout << "game: SDL2 Shutdown...\n"; TTF_Quit(); SDL_Quit(); } // release the joysticks if initalized void release_joysticks() { if(joysticks.size() == 0) { std::cout << "game: No joysticks to shutdown...\n"; } for(std::vector<SDL_Joystick *>::size_type i = 0; i < joysticks.size(); ++i) { std::cout << "game: Closing: " << SDL_JoystickName(joysticks[i]) << "\n"; SDL_JoystickClose(joysticks[i]); } } // initalize the joysticks if available void init_joysticks() { for(int i = 0; i < SDL_NumJoysticks(); ++i) { SDL_Joystick *stick = SDL_JoystickOpen(i); if(stick != NULL) { std::cout << "game: Openeed Joystick: " << SDL_JoystickName(stick) << "\n"; joysticks.push_back(stick); } } if(joysticks.size() == 0) std::cout << "game: No Joysticks found.\n"; } // release image files void release_images() { for(std::vector<SDL_Surface*>::size_type i = 0; i < surfaces.size(); ++i) { SDL_FreeSurface(surfaces[i]); std::cout << "released image index: [" << i << "]\n"; } if(!surfaces.empty()) surfaces.erase(surfaces.begin(), surfaces.end()); for(std::vector<TTF_Font *>::size_type i = 0; i< fonts.size(); ++i) { TTF_CloseFont(fonts[i]); std::cout << "released font index: [" << i << "]\n"; } if(!fonts.empty()) fonts.erase(fonts.begin(), fonts.end()); for(std::vector<SDL_Texture *>::size_type i = 0; i < textures.size(); ++i) { SDL_DestroyTexture(textures[i]); } if(!textures.empty()) textures.erase(textures.begin(), textures.end()); } // release resources virtual void releaseResources() override { release_images(); } // draw image at x,y void drawAt(Image image, int x, int y) override { SDL_Rect rc = { x, y, surfaces[image]->w, surfaces[image]->h }; SDL_BlitSurface(surfaces.at(image), 0, surface, &rc); } // draw at rect x,y,w,h void drawAtRect(Image image, int x, int y, int w, int h) override { SDL_Rect rc = { x, y, w, h }; SDL_BlitSurface(surfaces.at(image), 0, surface, &rc); } // draw at source rect dest rect void drawAtRect(Image image, int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) override { SDL_Rect rc = { x1, y1, w1, h1 }; SDL_Rect rc2 = { x2, y2, w2, h2 }; SDL_BlitSurface(surfaces.at(image), &rc, surface, &rc2); } // print text with font void printText(Font font, int x, int y, const std::string &text, const Color &col) override { SDL_Color col_s = { col.r, col.g, col.b }; SDL_Surface *surf = TTF_RenderText_Solid(fonts.at(font), text.c_str(), col_s); SDL_Rect rc = { x, y, surf->w, surf->h }; SDL_BlitSurface(surf, 0, surface, &rc); SDL_FreeSurface(surf); } // draw At point void drawAt(Image image, const Point &p) override { drawAt(image, p.x, p.y); } // draw at rect void drawAtRect(Image image, const Rect &r) override { drawAtRect(image, r.x, r.y, r.w, r.h); } // draw at rect source rect, destination rect void drawAtRect(Image image, const Rect &src, const Rect &dst) override { drawAtRect(image, src.x, src.y, src.w, src.h, dst.x, dst.y, dst.w, dst.h); } // print text at Point with color void printText(Font font, const Point &p, const std::string &text, const Color &col) override { printText(font, p.x, p.y, text, col); } // load texture Texture loadTexture(const std::string &text) override { SDL_Surface *surf = SDL_LoadBMP(text.c_str()); if(!surf) { std::cerr << "Error creating surface from: " << text << "\n"; exit(EXIT_FAILURE); } SDL_Texture *t = SDL_CreateTextureFromSurface(ren, surf); if(!t) { std::cerr << "Error creating texture...\n"; exit(EXIT_FAILURE); } textures.push_back(t); return textures.size()-1; } // return Image size virtual Size imageSize(Image img) override { if(img >= 0 && img < static_cast<int>(surfaces.size())) { return Size(surfaces[img]->w, surfaces[img]->h); } return Size(0, 0); } // draw texture at rect void drawTextureAtRect(Texture tex, const Rect &r) override { SDL_Rect rc = { r.x, r.y, r.w, r.h }; SDL_RenderCopy(ren, textures.at(tex), 0, &rc); } // load image file with default color key Image loadImage(const std::string &text) override { return loadImage(text, Color(255,255,255)); } // load image file with color key Image loadImage(const std::string &text, const Color &color) override { SDL_Surface *surface = SDL_LoadBMP(text.c_str()); if(!surface) { std::cerr << "Error could not load surface: " << text << "\n"; exit(EXIT_FAILURE); } surfaces.push_back(surface); int index = surfaces.size()-1; setImageColorKey(index, color); std::cout << "loaded image [" << text << "] at index: [" << index << "]\n"; return index; } // load image file from byte stream with color key Image loadImage(char *buf, int32_t size, const Color &c) override { SDL_RWops *ops = SDL_RWFromMem(buf, size); SDL_Surface *surface = SDL_LoadBMP_RW(ops, 1); if(!surface) { std::cerr << "Error could not load surface from memory \n"; exit(EXIT_FAILURE); } surfaces.push_back(surface); int index = surfaces.size()-1; setImageColorKey(index, c); std::cout << "loaded image at index: [" << index << "]\n"; return index; } // set Image color key void setImageColorKey(Image image, const Color &c) override { SDL_SetColorKey(surfaces[image], SDL_TRUE, SDL_MapRGB(surfaces[image]->format, c.r, c.g, c.b)); } // load font Image loadFont(const std::string &text, int size) override { TTF_Font *font = TTF_OpenFont(text.c_str(), size); if(!font) { std::cerr << "Error could not load font: " << text << "\n" << SDL_GetError() << "\n"; exit(EXIT_FAILURE); } fonts.push_back(font); int index = fonts.size()-1; std::cout << "loaded font [" << text << "] at index: [" << index << "]\n"; return index; } void update() { } // initalize subsystem bool init(const std::string &text, int w, int h) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { std::cerr << "Error initaliziing SDL\n"; return false; } srand(static_cast<unsigned int>(time(0))); TTF_Init(); window = SDL_CreateWindow(text.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_SHOWN); if(!window) { std::cerr << "Error creating window: " << SDL_GetError() << "...\n"; return false; } ren = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if(!ren) { std::cerr << "Error creating Renderer: " << SDL_GetError() << "\n"; return false; } tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 1280-16, 720-16); if(!tex) { std::cerr << "Could not create texture: " << SDL_GetError() << "\n"; return false; } surface = SDL_CreateRGBSurfaceFrom(NULL, 1280-16, 720-16, 32, w*4, 0x00FF0000, 0x0000FF00,0x000000FF,0xFF000000); if(!surface) { std::cerr << "Could not create main surface: " << SDL_GetError() << "\n"; return false; } init_joysticks(); width = w; height = h; return true; } // get system time ticks unsigned int getTicks() override { return static_cast<unsigned int>(SDL_GetTicks()); } // is Key or joybutton pressed? bool keyDown(const Key &c) override { const Uint8 *keys = SDL_GetKeyboardState(0); switch(c) { case Key::KEY_LEFT: if(keys[SDL_SCANCODE_LEFT]) return true; break; case Key::KEY_RIGHT: if(keys[SDL_SCANCODE_RIGHT]) return true; break; case Key::KEY_UP: if(keys[SDL_SCANCODE_UP]) return true; break; case Key::KEY_DOWN: if(keys[SDL_SCANCODE_DOWN]) return true; break; case Key::KEY_A: if(keys[SDL_SCANCODE_A]) return true; break; case Key::KEY_S: if(keys[SDL_SCANCODE_S]) return true; break; case Key::KEY_R: if(keys[SDL_SCANCODE_R]) return true; break; } for(std::vector<SDL_Joystick *>::size_type i = 0; i < joysticks.size(); ++i) { if(c == Key::KEY_A && SDL_JoystickGetButton(joysticks[i], 0)) { return true; } if(c == Key::KEY_S && SDL_JoystickGetButton(joysticks[i], 1)) { return true; } if(c == Key::KEY_LEFT && SDL_JoystickGetAxis(joysticks[i], 0) < -200) { return true; } if(c == Key::KEY_RIGHT && SDL_JoystickGetAxis(joysticks[i], 0) > 200) { return true; } if(c == Key::KEY_UP && SDL_JoystickGetAxis(joysticks[i], 1) > -200) { return true; } if(c == Key::KEY_DOWN && SDL_JoystickGetAxis(joysticks[i], 1) > 200) { return true; } } return false; } }; bool Window::active; GameObject *Window::current_object = nullptr; SDL_RenderObject render_object; // create window bool Window::createWindow(const std::string &text, int w, int h) { return render_object.init(text, w, h); } // set GameObject void Window::setObject(GameObject *obj) { Window::current_object = obj; } // intalize game object with render object void Window::init_object(GameObject *obj) { obj->init(&render_object); } // enter game loop int Window::loop() { if(current_object == nullptr) { std::cerr << "Error must initalize a game object.\n"; return EXIT_FAILURE; } SDL_Event e; active = true; while (active) { SDL_RenderClear(render_object.ren); SDL_LockTexture(render_object.tex, 0, &render_object.surface->pixels, &render_object.surface->pitch); SDL_FillRect(render_object.surface, 0, 0); current_object->draw(&render_object); SDL_UnlockTexture(render_object.tex); SDL_Rect rc = { 0, 0, render_object.width, render_object.height }; SDL_RenderCopy(render_object.ren, render_object.tex, 0, &rc); SDL_RenderPresent(render_object.ren); while(SDL_PollEvent(&e)) { switch(e.type) { case SDL_QUIT: active = false; break; case SDL_KEYDOWN: if(e.key.keysym.sym == SDLK_ESCAPE) active = false; current_object->keydown(e.key.keysym.sym); break; case SDL_KEYUP: current_object->keyup(e.key.keysym.sym); break; } } } current_object->release(&render_object); return EXIT_SUCCESS; } }