Async sprites loading

This commit is contained in:
Thomas 2022-01-10 14:27:16 +01:00
parent 3dcdcadff3
commit 36d6b21613
No known key found for this signature in database
GPG Key ID: E538821A6CDFDAD7
21 changed files with 254 additions and 123 deletions

View File

@ -17,3 +17,4 @@ target_link_libraries(Space mingl)
target_link_libraries(Space GL)
target_link_libraries(Space GLU)
target_link_libraries(Space glut)
target_link_libraries(Space pthread)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,7 @@
# General configuration
general:
maxFPS: 90
theme: bad
# Players config
players:

View File

@ -25,7 +25,12 @@ typedef string configKey;
* @brief this struct stores all relevant data from the configuration file
*/
struct ConfigData {
/*!
* @brief theme to use. Valid values : good,bad
*/
string theme;
/*!
* @brief maximum framerate at which the game will run
*/

View File

@ -14,7 +14,7 @@
#define GUARD_GAME_H
#include <vector>
#include "mingl/mingl.h"
#include "pixelManager.h"
#include "pixelManager/pixelManager.h"
#include "utils.h"
#include "playerDef.h"
#include "player.h"
@ -41,8 +41,9 @@ private:
/*!
* @brief PixelManager : Class that contains and draws all the data that will be drawn on screen
* This is a pointer because the object is allocated at runtime, following the configuration
*/
PixelManager pm;
unique_ptr<PixelManager> pm;
/*!
* @brief ConfigData : Struct that stores all the relevant data read from the configuration file
@ -65,7 +66,7 @@ private:
Position basePos;
/*!
* @brief Invader posision and type matrix
* @brief Invader position and type matrix
*/
InvadersGrid grid;
@ -97,9 +98,9 @@ private:
// invaders related variables
/*!
* @brief cooldown between two invader shot in milliseconds
* @brief cooldown until the invaders can shoot again
*/
unsigned fireCooldown=120;
unsigned fireCooldown=0;
// basic methods

16
headers/mySprite.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef GUARD_MYSPRITE_H
#define GUARD_MYSPRITE_H
#include <future>
#include "mingl/gui/sprite.h"
using namespace std;
class MySprite{
public:
unique_ptr<nsGui::Sprite> ptr;
future<void> asyncLoad(const string& fname);
void mirror(MySprite& msp);
};
#endif

View File

@ -0,0 +1,21 @@
#ifndef GUARD_GOODPIXELMANAGER_H
#define GUARD_GOODPIXELMANAGER_H
#include "pixelManager/pixelManager.h"
class GoodPixelManager : public PixelManager{
void loadSprites(SpriteTasks& tasks) override;
MySprite player;
MySprite invaderA;
MySprite invaderB;
MySprite invaderC;
MySprite missile;
MySprite torpedo;
public:
GoodPixelManager(MinGL& win);
};
#endif

View File

@ -24,54 +24,64 @@
#include "utils.h"
#include "playMode.h"
#include "menu.h"
#include "mySprite.h"
using namespace std;
#define MIRROR(SP) mirrorData((SP).getPixelData(), (SP).getRowSize()), (SP).getRowSize()
typedef nsGui::GlutFont::GlutFonts Font;
/*!
* @class PixelManager
* @brief main display function, clear the window and calls sub display functions
*/
/*
* It's MinGL's fault. This is all I have to say
*/
// The convention seems to just add a number to the macro name
#define ADD_TASK(X) ADD_TASK2(X, X)
#define ADD_TASK2(X, Y) tasks.push_back((X).asyncLoad("assets/"#Y".si2"));
typedef vector<future<void>> SpriteTasks;
class PixelManager{
public:
MinGL& window;
/*
* Sprites are not const because for some reason the texture is associated with coordinates,
* and we have no way to dissociate them...
* So the objects are constantly updated with new coordinates as they need to be drawn
* We used {} insead of () for the constructor because the () makes the compiler think we declare methods
*
* (We could copy them every time, but I feel like copying image data every frame isn't great)
*/
/*!
* @brief loads sprites in parallel using multiple threads
* @param[in] vec : We take his ownership, so
* @fn void loadSprites();
*/
virtual void loadSprites(SpriteTasks& tasks);
/*!
* @brief sprite of the logo of the game
*/
nsGui::Sprite logo{"assets/logo.si2"};
/*!
* @brief sprite of the background during gameplay
*/
nsGui::Sprite gameBackground{"assets/game_background.si2"};
MySprite logo;
/*!
* @brief sprite of the background during menu
*/
nsGui::Sprite menuBackground{"assets/menu_background.si2"};
MySprite menuBackground;
/*!
* @brief sprite of the background during gameplay
*/
MySprite gameBackground;
/*!
* @brief sprite of the right hand of god
*/
nsGui::Sprite rightHand{"assets/hand_open.si2"};
MySprite rightHand;
/*!
* @brief sprite of the left hand of god
*/
nsGui::Sprite leftHand{MIRROR(rightHand)};
MySprite leftHand;
/*!
* @brief constructor the pixel manager class
@ -145,11 +155,11 @@ public:
/*!
* @brief display a sprite on screen
* @param[in] sprite : sprite to draw
* @param[in] msp : sprite to draw
* @param[in] pos : pixel coordinates to draw the sprite
* @fn void drawSprite(const nsGui::Sprite& sprite, const Position& pos = Position(0, 0)) const;
* @fn void drawSprite(const MySprite& msp, const Position& pos = Position(0, 0)) const;
*/
void drawSprite(const nsGui::Sprite& sprite, const Position& pos = Position(0, 0)) const;
void drawSprite(const MySprite& msp, const Position& pos = Position(0, 0)) const;
/*!
* @brief display a menu button on screen

View File

@ -153,6 +153,7 @@ void ConfigBuilder::readInvaderType(const configKey& baseKey, InvaderTypeDef& in
void ConfigBuilder::readConfig() {
collectedData.theme = getString("general.theme");
collectedData.maxFPS = getInt("general.maxFPS");
readGrid("grid");

View File

@ -16,7 +16,7 @@
* The more important stuff must be drawn last
*/
void Game::displayAll() const {
pm.drawSprite(pm.gameBackground);
pm->drawSprite(pm->gameBackground);
for (unsigned i = 0; i < this->grid.size(); ++i){
for (unsigned j = 0; j < this->grid[i].size(); ++j){
Position vec(
@ -28,23 +28,23 @@ void Game::displayAll() const {
}
for(const missile& miss : missiles){
pm.drawMissile(miss, confData.missilesWidth, confData.missilesColor);
pm->drawMissile(miss, confData.missilesWidth, confData.missilesColor);
}
for(const Torpedo& tor : torpedos){
pm.drawTorpedo(tor, confData.torpedosWidth, confData.torpedosColor);
pm->drawTorpedo(tor, confData.torpedosWidth, confData.torpedosColor);
}
displayGod();
DEBUG_INSTR(
pm.drawText(Position(pm.getScreenWidth()-200, 20), "FPS : "+to_string(fps), nsGraphics::KWhite, Font::BITMAP_8_BY_13);
pm->drawText(Position(pm->getScreenWidth()-200, 20), "FPS : "+to_string(fps), nsGraphics::KWhite, Font::BITMAP_8_BY_13);
)
for(unsigned i=0;i<players.size();++i){
if(!players[i].isEliminated()){
if(players[i].deathAnimCounter%2==0){
pm.drawPlayer(players[i].x, confData.playersWidth, confData.playerDefs[i].color);
pm->drawPlayer(players[i].x, confData.playersWidth, confData.playerDefs[i].color);
}
}
// out of the condition, because we still need to display the falling heart
@ -57,15 +57,15 @@ void Game::displayHearts(playerID pID) const {
// As said before, the player loop is an illusion, 2 players max
unsigned x;
if(pID==PLAYER1)x = 0;
else x = pm.getScreenWidth()-HEART_LENGTH;
else x = pm->getScreenWidth()-HEART_LENGTH;
unsigned y = GOD_BENCH_SIZE+5;
for(unsigned i=0;i<players[pID].lives;++i){
pm.drawHeart(Position(x, y));
pm->drawHeart(Position(x, y));
y+=HEART_LENGTH+5;
}
if(players[pID].hasDeathAnimation()){
pm.drawHeart(Position(x, y+players[pID].deathAnimCounter*5));
pm->drawHeart(Position(x, y+players[pID].deathAnimCounter*5));
}
}
@ -74,15 +74,15 @@ void Game::displayInvader(const Position& pos, InvaderType type) const {
const InvaderTypeDef& invDef = confData.invadersDef.at(type);
switch(type){
case InvaderType::TYPEA:{
pm.drawInvaderA(pos, confData.invadersSize, invDef.color);
pm->drawInvaderA(pos, confData.invadersSize, invDef.color);
return;
}
case InvaderType::TYPEB:{
pm.drawInvaderB(pos, confData.invadersSize, invDef.color);
pm->drawInvaderB(pos, confData.invadersSize, invDef.color);
return;
}
case InvaderType::TYPEC:{
pm.drawInvaderC(pos, confData.invadersSize, invDef.color);
pm->drawInvaderC(pos, confData.invadersSize, invDef.color);
return;
}
}
@ -97,40 +97,40 @@ void Game::displayGod() const {
case GodState::NONE:
return;
case GodState::AWAKE: {
pm.drawGodBench(god.counter - GOD_BENCH_SIZE);
pm->drawGodBench(god.counter - GOD_BENCH_SIZE);
Position leftHand(GOD_HAND_DISTANCE, god.counter-GOD_BENCH_SIZE);
Position rightHand(pm.getScreenWidth()-GOD_HAND_DISTANCE-GOD_HAND_SIZE, god.counter-GOD_BENCH_SIZE);
pm.drawGodLeftHand(leftHand);
pm.drawGodRightHand(rightHand);
pm.drawGodFace(god.counter - GOD_BENCH_SIZE);
Position rightHand(pm->getScreenWidth()-GOD_HAND_DISTANCE-GOD_HAND_SIZE, god.counter-GOD_BENCH_SIZE);
pm->drawGodLeftHand(leftHand);
pm->drawGodRightHand(rightHand);
pm->drawGodFace(god.counter - GOD_BENCH_SIZE);
break;
}
case GodState::WAIT:{
pm.drawGodBench(0);
pm->drawGodBench(0);
Position leftHand(GOD_HAND_DISTANCE, 0);
Position rightHand(god.getRightHandPos(pm.getScreenWidth()));
pm.drawGodLeftHand(leftHand);
pm.drawGodRightHand(rightHand);
pm.drawGodFace(0);
Position rightHand(god.getRightHandPos(pm->getScreenWidth()));
pm->drawGodLeftHand(leftHand);
pm->drawGodRightHand(rightHand);
pm->drawGodFace(0);
break;
}
case GodState::RETRIEVE1:
case GodState::RETRIEVE2:{
// Bezier curve
// counter goes [0-100]
pm.drawGodBench(0);
pm.drawGodLeftHand(Position(GOD_HAND_DISTANCE, 0));
pm.drawGodFace(0);
pm->drawGodBench(0);
pm->drawGodLeftHand(Position(GOD_HAND_DISTANCE, 0));
pm->drawGodFace(0);
Position pos(god.getRightHandPos(pm.getScreenWidth()));
Position pos(god.getRightHandPos(pm->getScreenWidth()));
Position endPos = invIndexToPos(god.thrownInvPosX, god.thrownInvPosY);
applyBezier(pos, god.thrownTransition, god.counter / 100.0);
applyBezier(pos, endPos, god.counter / 100.0);
// pos is now the position we need to draw our hand to
pm.drawGodRightHand(pos);
pm->drawGodRightHand(pos);
if(god.thrownInvType!=InvaderType::NONE){
pos+=Position(GOD_HAND_SIZE/2, GOD_HAND_SIZE/2);
@ -140,12 +140,12 @@ void Game::displayGod() const {
break;
}
case GodState::THROW:{
pm.drawGodBench(0);
pm.drawGodLeftHand(Position(GOD_HAND_DISTANCE, 0));
pm.drawGodFace(0);
pm->drawGodBench(0);
pm->drawGodLeftHand(Position(GOD_HAND_DISTANCE, 0));
pm->drawGodFace(0);
// compute start position (not sure if we should store it or compute it each time ?)
Position handPos = god.getRightHandPos(pm.getScreenWidth());
Position handPos = god.getRightHandPos(pm->getScreenWidth());
Position invaderPos = handPos;
applyTransformation(invaderPos, GOD_HAND_SIZE, confData.invadersSize);
@ -160,7 +160,7 @@ void Game::displayGod() const {
else handCounter = 30-god.counter;
handPos = handPos + god.thrownVector * (handCounter / 100.0);
}
pm.drawGodRightHand(handPos);
pm->drawGodRightHand(handPos);
break;
}

View File

@ -10,17 +10,42 @@
*/
#include <chrono>
#include <memory>
#include <thread>
#include "game.h"
#include "playMode.h"
#include "pixelManager/goodPixelManager.h"
#define WININIT window("SUPER Space Invader : Turbo Apocalypse DX - VS GOD", Position(1280, 720), Position(128, 128), nsGraphics::KBlack)
Game::Game() : WININIT, pm(window) {
if(!reloadConfig()){
Game::Game() : WININIT {
if(!reloadConfig()){ // Config
throw runtime_error("Initial config loading failed. Please check the error above and fix the configuration");
}
sm.readFile();
// Pixel Manager
if(confData.theme=="good"){
pm = std::make_unique<GoodPixelManager>(window);
}else if(confData.theme=="bad"){
pm = std::make_unique<PixelManager>(window);
}else throw runtime_error("Invalid theme value : "+confData.theme+
"\nValid values are : good,bad");
cout << "Loading sprites..." << endl;
SpriteTasks tasks;
chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now();
pm->loadSprites(tasks);
for(future<void>& f : tasks)f.wait();
// We just do that for one sprite, so I didn't bother creating an 'API' for that
pm->leftHand.mirror(pm->rightHand);
chrono::high_resolution_clock::duration elapsed = chrono::high_resolution_clock::now()-start;
cout << "Done ! Time : " << chrono::duration_cast<chrono::milliseconds>(elapsed).count() << "ms" << endl;
sm.readFile(); // Score manager
}
bool Game::areThereInvadersLeft(){
@ -30,7 +55,7 @@ bool Game::areThereInvadersLeft(){
void Game::handleScoreSaving(){
for(unsigned i=0;i<players.size();++i){
string pName;
pm.askPlayerNameMenu(i, players[i].score, pName);
pm->askPlayerNameMenu(i, players[i].score, pName);
sm.inputScore(move(pName), players[i].score);
}
sm.writeFile();
@ -42,13 +67,13 @@ void Game::managedGames() {
while(playMode!=PlayMode::EXIT){
if(playMode==PlayMode::NONE){
playMode = pm.showInitialMenu();
playMode = pm->showInitialMenu();
}else{
initGame();
enterGameLoop(); // will read the playMode
handleScoreSaving();
cout << "END OF GAME" << endl;
if(!pm.showDeathMenu())playMode = PlayMode::NONE;
if(!pm->showDeathMenu())playMode = PlayMode::NONE;
}
}
}
@ -69,7 +94,7 @@ void Game::initGame(){
}else{
players.resize(2);
// mirror the start X Position for the other
players[1].x = pm.getScreenWidth() - confData.startXPosition - confData.playersWidth;
players[1].x = pm->getScreenWidth() - confData.startXPosition - confData.playersWidth;
}
players[0].x = confData.startXPosition;
@ -103,7 +128,7 @@ WinValue Game::enterGameLoop(){ // returns when game is finished
fpsStartTime = startTime;
}
pm.startFrame();
pm->startFrame();
managePlayers();
if(manageInvaders()) { // if they went down
@ -126,7 +151,7 @@ WinValue Game::enterGameLoop(){ // returns when game is finished
displayAll();
pm.endFrame();
pm->endFrame();
MyTimePoint endTime = chrono::high_resolution_clock::now();

View File

@ -20,7 +20,7 @@ void Game::manageOnePlayer(playerID pID){
else p.x -= confData.playersSpeed;
}
if (ISPRESSED(pID, right)){
if(p.x + confData.playersWidth + confData.playersSpeed >= pm.getScreenWidth()) p.x = pm.getScreenWidth() - confData.playersWidth - 1;
if(p.x + confData.playersWidth + confData.playersSpeed >= pm->getScreenWidth()) p.x = pm->getScreenWidth() - confData.playersWidth - 1;
else p.x += confData.playersSpeed;
}
@ -35,7 +35,7 @@ void Game::manageOnePlayer(playerID pID){
if(p.fireCooldown==0) {
if (ISPRESSED(pID, shoot)) {
torpedos.emplace_back(p.x + confData.playersWidth / 2, pm.getScreenHeight() - PLAYER_HEIGHT, pID);
torpedos.emplace_back(p.x + confData.playersWidth / 2, pm->getScreenHeight() - PLAYER_HEIGHT, pID);
p.fireCooldown = confData.playersFireCooldown;
}
}else --p.fireCooldown;
@ -69,7 +69,7 @@ bool Game::manageInvaders(){
// you got the end position of the invader crowd !
if(end + confData.invadersSpeed < pm.getScreenWidth()){
if(end + confData.invadersSpeed < pm->getScreenWidth()){
basePos.setX(basePos.getX() + confData.invadersSpeed);
}else{
basePos.setY(basePos.getY() + confData.invadersSize + confData.invadersDistance);
@ -121,7 +121,7 @@ void Game::remCollidingProjectiles(){
void Game::moveMissiles() {
auto miss = missiles.begin();
while (miss != missiles.end()) {
if (miss->getY() >= pm.getScreenHeight())missiles.erase(miss);
if (miss->getY() >= pm->getScreenHeight())missiles.erase(miss);
else {
miss->setY(miss->getY()+confData.missilesSpeed);
++miss;
@ -144,7 +144,7 @@ void Game::checkMissilesAndPlayers() {
auto miss_ite = missiles.begin();
while(miss_ite!=missiles.end()){
bool wasColliding = false;
if(miss_ite->getY()>=pm.getScreenHeight()-PLAYER_HEIGHT){ // check collision on Y
if(miss_ite->getY()>=pm->getScreenHeight()-PLAYER_HEIGHT){ // check collision on Y
// now check collision on X (with both players)
for(Player& p : players){
if(p.isPlaying()){
@ -206,6 +206,6 @@ bool Game::invadersTouchPlayer() const {
unsigned outter = line.getOutterInvader();
return this->basePos.getY()+confData.invadersSize*(outter+1)
+confData.invadersDistance*outter
>= pm.getScreenHeight() - PLAYER_HEIGHT;
>= pm->getScreenHeight() - PLAYER_HEIGHT;
});
}

View File

@ -48,7 +48,7 @@ bool Game::manageGod() {
god.thrownInvPosY = grid[god.thrownInvPosX].randomValidInv();
god.thrownInvType = InvaderType::NONE;
god.thrownTransition.setX(pm.getScreenWidth() - GOD_HAND_DISTANCE - GOD_HAND_SIZE);
god.thrownTransition.setX(pm->getScreenWidth() - GOD_HAND_DISTANCE - GOD_HAND_SIZE);
god.thrownTransition.setY(basePos.getY() + INV_GET_POS(god.thrownInvPosY));
return false;
}
@ -79,7 +79,7 @@ bool Game::manageGod() {
// compute the launch vector
Position invaderMiddlePos(pm.getScreenWidth() - GOD_HAND_DISTANCE - GOD_HAND_SIZE / 2,
Position invaderMiddlePos(pm->getScreenWidth() - GOD_HAND_DISTANCE - GOD_HAND_SIZE / 2,
GOD_HAND_SIZE / 2);
@ -90,7 +90,7 @@ bool Game::manageGod() {
* honestly at this point I want to re-code the whole game engine to allow a better handling of cases like this...*/
Position playerMiddlePos(players[target].x + confData.playersWidth / 2,
pm.getScreenHeight() - PLAYER_HEIGHT / 2);
pm->getScreenHeight() - PLAYER_HEIGHT / 2);
god.thrownVector = playerMiddlePos - invaderMiddlePos;
god.thrownVector = god.thrownVector / (god.thrownVector.computeMagnitude() / 1000.0);
@ -101,7 +101,7 @@ bool Game::manageGod() {
case GodState::THROW: {
++god.counter;
Position invaderPos = god.getRightHandPos(pm.getScreenWidth());
Position invaderPos = god.getRightHandPos(pm->getScreenWidth());
applyTransformation(invaderPos, GOD_HAND_SIZE, confData.invadersSize);
Position a = god.thrownVector * (god.counter / 100.0);
invaderPos = invaderPos + a;
@ -109,8 +109,8 @@ bool Game::manageGod() {
bool touched = false;
// check if OOB (Out Of Bounds)
if (invaderPos.getY() + confData.invadersSize >= pm.getScreenWidth() ||
(invaderPos.getX() < 0 || invaderPos.getX() + confData.invadersSize >= pm.getScreenWidth())) {
if (invaderPos.getY() + confData.invadersSize >= pm->getScreenWidth() ||
(invaderPos.getX() < 0 || invaderPos.getX() + confData.invadersSize >= pm->getScreenWidth())) {
touched = true;
/* there are no invaders in the grid anymore, and the one thrown just went out of bound
@ -118,7 +118,7 @@ bool Game::manageGod() {
if(!areThereInvadersLeft())return true;
// check player collision
} else if (invaderPos.getY() + confData.invadersSize >= pm.getScreenHeight() - PLAYER_HEIGHT) {
} else if (invaderPos.getY() + confData.invadersSize >= pm->getScreenHeight() - PLAYER_HEIGHT) {
for (Player &p: players) {
if(p.isPlaying()){
if (areLinesColliding(

26
src/mySprite.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "utils.h"
#include "mySprite.h"
future<void> MySprite::asyncLoad(const string& fname){
return std::async(std::launch::async, [fname, this]() -> void {
ptr = std::make_unique<nsGui::Sprite>(fname);
});
}
void MySprite::mirror(MySprite& msp) {
const vector<RGBAcolor>& inPixels = msp.ptr->getPixelData();
unsigned rowSize = msp.ptr->getRowSize();
vector<RGBAcolor> outPixels;
// we reserve size so the vector doesn't dynamically grows
outPixels.reserve(inPixels.size());
//for each line of pixel
for(unsigned rowOffset=0; rowOffset < inPixels.size(); rowOffset+=rowSize){
// for each pixel of that line
for(unsigned j=0;j<rowSize;++j) {
// push back the pixel opposed to this one (still in the same line)
outPixels.push_back(inPixels[rowOffset + rowSize - j - 1]);
}
}
ptr = std::make_unique<nsGui::Sprite>(outPixels, rowSize);
}

View File

@ -11,7 +11,7 @@
*/
#include "mingl/gui/text.h"
#include "pixelManager.h"
#include "pixelManager/pixelManager.h"
#include "utils.h"
#include "god.h"
@ -76,26 +76,10 @@ void PixelManager::drawTorpedo(const Position& baseVector, unsigned width, const
window << Rectangle(baseVector, baseVector + Position(width, width * PROJ_LENGTH_FACTOR), color);
}
void PixelManager::drawSprite(const Sprite& sprite, const Position& pos) const {
// see pixelManager.h for the explanation of this hack
const_cast<Sprite&>(sprite).setPosition(pos);
sprite.draw(window);
}
unsigned PixelManager::getScreenHeight() const {
return window.getWindowSize().getY();
}
unsigned PixelManager::getScreenWidth() const {
return window.getWindowSize().getX();
}
void PixelManager::startFrame() const {
window.clearScreen();
}
void PixelManager::endFrame() const {
window.finishFrame();
void PixelManager::drawSprite(const MySprite& msp, const Position& pos) const {
// The sprite is associated with a Vec2D for whatever reason, so yeah, we modify it each time we draw it
msp.ptr->setPosition(pos);
msp.ptr->draw(window);
}
void PixelManager::drawGodBench(int y) const {
@ -128,19 +112,3 @@ void PixelManager::drawGodFace(int y, bool angry) const {
void PixelManager::drawText(const Position& pos, const string& text, const nsGraphics::RGBAcolor& color, Font font) const {
window << Text(pos, text, color, font);
}
vector<RGBAcolor>
PixelManager::mirrorData(const vector<nsGraphics::RGBAcolor>& inPixels, unsigned rowSize) {
vector<RGBAcolor> outPixels;
// we reserve size so the vector doesn't dynamically grows
outPixels.reserve(inPixels.size());
//for each line of pixel
for(unsigned rowOffset=0; rowOffset < inPixels.size(); rowOffset+=rowSize){
// for each pixel of that line
for(unsigned j=0;j<rowSize;++j) {
// push back the pixel opposed to this one (still in the same line)
outPixels.push_back(inPixels[rowOffset + rowSize - j - 1]);
}
}
return std::move(outPixels);
}

View File

@ -13,13 +13,13 @@
#include <thread>
#include "mingl/shape/rectangle.h"
#include "playMode.h"
#include "pixelManager.h"
#include "pixelManager/pixelManager.h"
#include "utils.h"
using namespace nsShape;
using namespace nsGraphics;
void PixelManager::displayButton(const Position& baseVector,const string& text,nsGraphics::RGBAcolor& color){
void PixelManager::displayButton(const Position& baseVector, const string& text, nsGraphics::RGBAcolor& color){
window << Rectangle(baseVector, Position(180, 40)+baseVector, KGray);
window << Rectangle(baseVector+Position(2,2), Position(178, 38)+baseVector, KBlack);
window << nsGui::Text(baseVector+Position(10,22), text, color);

View File

@ -0,0 +1,15 @@
#include "pixelManager/goodPixelManager.h"
void GoodPixelManager::loadSprites(SpriteTasks& tasks) {
PixelManager::loadSprites(tasks);
ADD_TASK(player)
ADD_TASK(invaderA)
ADD_TASK(invaderB)
ADD_TASK(invaderC)
ADD_TASK(missile)
ADD_TASK(torpedo)
}
GoodPixelManager::GoodPixelManager(MinGL& win) : PixelManager(win) {
}

View File

@ -0,0 +1,41 @@
#include "pixelManager/pixelManager.h"
void PixelManager::loadSprites(SpriteTasks& tasks){
ADD_TASK(logo)
ADD_TASK(menuBackground)
ADD_TASK(gameBackground)
ADD_TASK2(rightHand, hand)
}
void PixelManager::startFrame() const {
window.clearScreen();
}
void PixelManager::endFrame() const {
window.finishFrame();
}
unsigned PixelManager::getScreenHeight() const {
return window.getWindowSize().getY();
}
unsigned PixelManager::getScreenWidth() const {
return window.getWindowSize().getX();
}
vector<RGBAcolor>
PixelManager::mirrorData(const vector<nsGraphics::RGBAcolor>& inPixels, unsigned rowSize) {
vector<RGBAcolor> outPixels;
// we reserve size so the vector doesn't dynamically grows
outPixels.reserve(inPixels.size());
//for each line of pixel
for(unsigned rowOffset=0; rowOffset < inPixels.size(); rowOffset+=rowSize){
// for each pixel of that line
for(unsigned j=0;j<rowSize;++j) {
// push back the pixel opposed to this one (still in the same line)
outPixels.push_back(inPixels[rowOffset + rowSize - j - 1]);
}
}
return std::move(outPixels);
}