void CCVideoLayerImpl::appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState, bool&) { ASSERT(CCProxy::isImplThread()); if (!m_frame) return; // FIXME: When we pass quads out of process, we need to double-buffer, or // otherwise synchonize use of all textures in the quad. IntRect quadRect(IntPoint(), bounds()); switch (m_format) { case GraphicsContext3D::LUMINANCE: { // YUV software decoder. const FramePlane& yPlane = m_framePlanes[WebKit::WebVideoFrame::yPlane]; const FramePlane& uPlane = m_framePlanes[WebKit::WebVideoFrame::uPlane]; const FramePlane& vPlane = m_framePlanes[WebKit::WebVideoFrame::vPlane]; OwnPtr<CCYUVVideoDrawQuad> yuvVideoQuad = CCYUVVideoDrawQuad::create(sharedQuadState, quadRect, yPlane, uPlane, vPlane); quadList.append(yuvVideoQuad.release()); break; } case GraphicsContext3D::RGBA: { // RGBA software decoder. const FramePlane& plane = m_framePlanes[WebKit::WebVideoFrame::rgbPlane]; float widthScaleFactor = static_cast<float>(plane.visibleSize.width()) / plane.size.width(); bool premultipliedAlpha = true; FloatRect uvRect(0, 0, widthScaleFactor, 1); bool flipped = false; OwnPtr<CCTextureDrawQuad> textureQuad = CCTextureDrawQuad::create(sharedQuadState, quadRect, plane.textureId, premultipliedAlpha, uvRect, flipped); quadList.append(textureQuad.release()); break; } case GraphicsContext3D::TEXTURE_2D: { // NativeTexture hardware decoder. bool premultipliedAlpha = true; FloatRect uvRect(0, 0, 1, 1); #if defined(OS_CHROMEOS) && defined(__ARMEL__) bool flipped = true; // Under the covers, implemented by OpenMAX IL. #elif defined(OS_WINDOWS) bool flipped = true; // Under the covers, implemented by DXVA. #else bool flipped = false; // LibVA (cros/intel), MacOS. #endif OwnPtr<CCTextureDrawQuad> textureQuad = CCTextureDrawQuad::create(sharedQuadState, quadRect, m_frame->textureId(), premultipliedAlpha, uvRect, flipped); quadList.append(textureQuad.release()); break; } case Extensions3DChromium::GL_TEXTURE_EXTERNAL_OES: { // StreamTexture hardware decoder. OwnPtr<CCStreamVideoDrawQuad> streamVideoQuad = CCStreamVideoDrawQuad::create(sharedQuadState, quadRect, m_frame->textureId(), m_streamTextureMatrix); quadList.append(streamVideoQuad.release()); break; } default: CRASH(); // Someone updated convertVFCFormatToGC3DFormat above but update this! } }
void ParticalBatch2D::draw(SpriteBatch* spriteBatch) { glm::vec4 uvRect(0.0f, 0.0f, 1.0f, 1.0f); for (int i{ 0 }; i < m_maxParticals; ++i) { auto& partical = m_particals[i]; if (partical.life > 0.0f) { glm::vec4 destRect(partical.position.x, partical.position.y, partical.width, partical.width); spriteBatch->draw(destRect, uvRect, m_texture.id, partical.color, 0.0f); } } }
void ParticleBatch2D::draw(SpriteBatch* spriteBatch) { glm::vec4 uvRect(0.0f, 0.0f, 1.0f, 1.0f); for (int i = 0; i < m_maxParticles; i++) { auto& p = m_particles[i]; if (m_particles[i].lifeTime > 0.0f) { glm::vec4 destRect(p.position.x, p.position.y, p.width, p.width); spriteBatch->draw(destRect, uvRect, m_texture.id, 0.0f, p.color); } } }
void Bullet::Draw(Engine2D::SpriteBatch & spriteBatch) { glm::vec4 destRect(_position.x + BULLET_RADIUS, _position.y + BULLET_RADIUS, BULLET_RADIUS * 2, BULLET_RADIUS * 2); glm::vec4 uvRect(0.0f, 0.0f, 1.0f, 1.0f); Engine2D::ColorRGBA8 c; c.r = 64; c.b = 64; c.g = 64; c.a = 255; spriteBatch.Draw(destRect, uvRect, Engine2D::ResourceManager::getTexture("Images/Player16x16.png").id, 0.0f, c); }
void ParticleBatch2D::draw(SpriteBatch* spriteBatch) { glm::vec4 uvRect(0.0f, 0.0f, 1.0f, 1.0f); for (int i = 0; i < m_maxParticles; i++) { // Check if it is active auto& p = m_particles[i]; if (p.m_life > 0.0f) { glm::vec4 destRect(p.m_position.x, p.m_position.y, p.m_width, p.m_width); spriteBatch->draw(destRect, uvRect, m_texture.id, 0.0f, p.m_color); } } }
//Draw all active particles void ParticleBatch2D::Draw(SpriteBatch* _spritebBatch) { glm::vec4 uvRect(0.0f, 0.0f, 1.0f, 1.0f); auto pointerToArray = m_particles.get(); for (int i = 0; i < m_maxParticles; i++) { // check if it is active Particle2D& particle = pointerToArray[i]; if (particle.m_life > 0.0f) { glm::vec4 destRect(particle.m_position.x, particle.m_position.y, particle.m_width, particle.m_width); _spritebBatch->Draw(destRect, uvRect, m_texture.id, 0.0f, particle.m_color); } } }
void CCScrollbarLayerImpl::appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState, bool&) { ScrollbarThemeComposite* theme = static_cast<ScrollbarThemeComposite*>(ScrollbarTheme::theme()); if (!theme) return; bool premultipledAlpha = false; FloatRect uvRect(0, 0, 1, 1); bool flipped = false; IntRect thumbRect = theme->thumbRect(&m_scrollbar); thumbRect.move(-m_scrollbar.x(), -m_scrollbar.y()); if (m_thumbTextureId && theme->hasThumb(&m_scrollbar) && !thumbRect.isEmpty()) { OwnPtr<CCTextureDrawQuad> quad = CCTextureDrawQuad::create(sharedQuadState, thumbRect, m_thumbTextureId, premultipledAlpha, uvRect, flipped); quad->setNeedsBlending(); quadList.append(quad.release()); } if (!m_backgroundTextureId) return; IntRect backgroundRect(IntPoint(), contentBounds()); quadList.append(CCTextureDrawQuad::create(sharedQuadState, backgroundRect, m_backgroundTextureId, premultipledAlpha, uvRect, flipped)); }
Level::Level(const std::string& fileName) { std::ifstream file; file.open(fileName); // Error checking if (file.fail()) { Engine2D::fatalError("Failed to open " + fileName); } _spriteBatch.Init(); _spriteBatch.Begin(); glm::vec4 uvRect(0.0f, 0.0f, 1.0f, 1.0f); Engine2D::ColorRGBA8 color; color.r = 255; color.g = 255; color.b = 255; color.a = 255; std::string tmp; while (std::getline(file, tmp)) { _levelData.push_back(tmp); } for (int y = 0; y < _levelData.size(); y++) { for (int x = 0; x < _levelData.size(); x++) { char tile = _levelData[y][x]; glm::vec4 destRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE); switch (tile) { case ' ': case '#': _spriteBatch.Draw(destRect, uvRect, Engine2D::ResourceManager::getTexture("Images/Wall16x16.png").id, 0.0f, color); break; // Door //_spriteBatch.Draw(destRect, uvRect, // Engine2D::ResourceManager::getTexture("Images/Door16x16.png").id, 0.0f, color); //break; case '@': _levelData[y][x] = '.'; _spriteBatch.Draw(destRect, uvRect, Engine2D::ResourceManager::getTexture("Images/Blank16x16.png").id, 0.0f, color); _startPlayerPos.x = x * TILE_SIZE; _startPlayerPos.y = y * TILE_SIZE; break; case 'Z': _levelData[y][x] = '.'; _spriteBatch.Draw(destRect, uvRect, Engine2D::ResourceManager::getTexture("Images/Blank16x16.png").id, 0.0f, color); _zombieStartPositions.emplace_back(x * TILE_SIZE, y * TILE_SIZE); break; case 'R': _levelData[y][x] = '.'; _spriteBatch.Draw(destRect, uvRect, Engine2D::ResourceManager::getTexture("Images/Blank16x16.png").id, 0.0f, color); _riflePosition = glm::vec2(x, y); break; case 'S': _levelData[y][x] = '.'; _spriteBatch.Draw(destRect, uvRect, Engine2D::ResourceManager::getTexture("Images/Blank16x16.png").id, 0.0f, color); _shotgunPosition = glm::vec2(x, y); break; case 'A': _levelData[y][x] = '.'; _spriteBatch.Draw(destRect, uvRect, Engine2D::ResourceManager::getTexture("Images/Blank16x16.png").id, 0.0f, color); _ammoPositions.emplace_back(x * TILE_SIZE, y * TILE_SIZE); break; default: _levelData[y][x] = '.'; _spriteBatch.Draw(destRect, uvRect, Engine2D::ResourceManager::getTexture("Images/Blank16x16.png").id, 0.0f, color); std::printf("Unknown tile %c at (%d, %d)", tile, x, y); break; case '<': case '>': case '+': case '.': case ',': _levelData[y][x] = '.'; _spriteBatch.Draw(destRect, uvRect, Engine2D::ResourceManager::getTexture("Images/Blank16x16.png").id, 0.0f, color); break; } } } _spriteBatch.End(); }
void Actor::draw(SpriteBatch& spriteBatch, const std::string& texturePath) { glm::vec4 destRect(m_position.x, m_position.y, ACTOR_WIDTH, ACTOR_HEIGHT); glm::vec4 uvRect(0.0f, 0.0f, 1.0f, 1.0f); ColorRGBA8 color(255, 255, 255, 255); spriteBatch.draw(destRect, uvRect, ResourceManager::getTexture(texturePath).id, m_position.y, color); }
Level::Level(const std::string& fileName) { // Load the spritesheet // TODO(Marzena): Maybe don't make it hard coded like this, so different levels can have different sprite sheets. _wallSprites.init("Textures/IsoWalls.png", 8, 8); _dungeonSprites.init("Textures/DungeonTiles.png", 8, 4); //Load the file std::ifstream file; file.open(fileName); //Error check if (file.fail()) { errors::fatalError("Failed to open " + fileName + "!"); } //Ignore the first string in tmpVar std::string tmpVar; file >> tmpVar >> _numHumans; //Throw away the rest of the first line std::getline(file, tmpVar); //Read the base layer of level data while (std::getline(file, tmpVar)) { charLevelFile[0].push_back(tmpVar); _levelData[0].emplace_back(tmpVar.size()); } // Set up top layer of tiles _levelData[1].resize(_levelData[0].size()); // Initialize each row for (size_t i = 0; i < _levelData[1].size(); i++) { _levelData[1][i].resize(_levelData[0][0].size()); } // Generate top layer here generateUpperLayer(); //Set up texture coordinate glm::vec4 uvRect(0.0f, 0.0f, 1.0f, 1.0f); //Set color <- enhance your engine, add color there instead! Color4 colorWhite; colorWhite.r = 255; colorWhite.g = 255; colorWhite.b = 255; colorWhite.a = 255; //Render all the tiles for (int z = 0; z < NUM_LAYERS; z++) { std::vector<std::vector<Tile>>& layerData = _levelData[z]; SpriteBatch& spriteBatch = _spriteBatch[z]; //Initialize SpriteBatch spriteBatch.init(); spriteBatch.begin(GlyphSortType::BACK_TO_FRONT); for (int y = 0; y < layerData.size(); y++) { for (int x = 0; x < layerData[y].size(); x++) { //Grab the tile char tileChar = charLevelFile[z][y][x]; Tile& tile = layerData[y][x]; const float TILE_SCALE = 2.0f; const float TILE_OFFSET = TILE_WIDTH * TILE_SCALE * 0.5f; glm::vec2 cartesianPosition(x * TILE_WIDTH + TILE_WIDTH, y * TILE_WIDTH + TILE_WIDTH); glm::vec2 isoPosition = utils::cartToIso(cartesianPosition); // Offset for layer isoPosition.y += z * TILE_WIDTH * TILE_SCALE; //Get dest rect glm::vec4 destRect(isoPosition.x - TILE_OFFSET, isoPosition.y - TILE_OFFSET, TILE_WIDTH * TILE_SCALE, TILE_WIDTH * TILE_SCALE); // Calculate depth using the Y screen position and the floor number float depth = isoPosition.y; //+ (NUM_LAYERS - z + 1) * DEPTH_PER_LAYER; //Process the tile switch (tileChar) { case 'R': spriteBatch.draw(destRect, _wallSprites.getUvRect(1, 1), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(1, 1); break; case 'P': spriteBatch.draw(destRect, _wallSprites.getUvRect(0, 1), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(0, 1); break; case 'L': spriteBatch.draw(destRect, _wallSprites.getUvRect(2, 1), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(2, 1); break; case '@': tile.isCollider = false; _startPlayerPos.x = x * TILE_WIDTH; _startPlayerPos.y = y * TILE_WIDTH; break; case 'Z': spriteBatch.draw(destRect, _dungeonSprites.getUvRect(0, 0), _dungeonSprites.getTexture().id, depth, colorWhite); _enemyStartPos.emplace_back(x * TILE_WIDTH, y * TILE_WIDTH); tile.setTextureOffset(0, 0); tile.isCollider = false; break; case ':': //Quest giver tile.isCollider = false; spriteBatch.draw(destRect, _dungeonSprites.getUvRect(0, 0), _dungeonSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(0, 0); _qGiverStartPos.x = x * TILE_WIDTH; _qGiverStartPos.y = y * TILE_WIDTH; break; case ';': //Boss tile.isCollider = false; spriteBatch.draw(destRect, _dungeonSprites.getUvRect(0, 0), _dungeonSprites.getTexture().id, isoPosition.y, colorWhite); tile.setTextureOffset(0, 0); _bossStartPos.x = x * TILE_WIDTH; _bossStartPos.y = y * TILE_WIDTH; break; case '!': //Ranged boss tile.isCollider = false; spriteBatch.draw(destRect, _dungeonSprites.getUvRect(0, 0), _dungeonSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(0, 0); _rangedBossStartPos.x = x * TILE_WIDTH; _rangedBossStartPos.y = y * TILE_WIDTH; break; case '.': spriteBatch.draw(destRect, _dungeonSprites.getUvRect(0, 0), _dungeonSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(0, 0); tile.isCollider = false; break; case '1': //Door spriteBatch.draw(destRect, _wallSprites.getUvRect(5, 1), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(5, 1); tile.isCollider = false; break; case '2': spriteBatch.draw(destRect, _wallSprites.getUvRect(6, 1), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(6, 1); tile.isCollider = false; break; case '3': spriteBatch.draw(destRect, _wallSprites.getUvRect(3, 1), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(3, 1); tile.isCollider = false; break; case '4': spriteBatch.draw(destRect, _wallSprites.getUvRect(4, 1), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(4, 1); tile.isCollider = false; break; case ',': // Top of pillar spriteBatch.draw(destRect, _wallSprites.getUvRect(0, 0), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(0, 0); break; case '[': // Wall facing right top spriteBatch.draw(destRect, _wallSprites.getUvRect(1, 0), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(1, 0); break; case ']': // Wall facing left top spriteBatch.draw(destRect, _wallSprites.getUvRect(2, 0), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(2, 0); break; case '<': // Door Top spriteBatch.draw(destRect, _wallSprites.getUvRect(5, 0), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(5, 0); break; case '>': // Door Top spriteBatch.draw(destRect, _wallSprites.getUvRect(6, 0), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(6, 0); break; case '|': // Door Top spriteBatch.draw(destRect, _wallSprites.getUvRect(3, 0), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(3, 0); break; case '/': // Door Top spriteBatch.draw(destRect, _wallSprites.getUvRect(4, 0), _wallSprites.getTexture().id, depth, colorWhite); tile.setTextureOffset(4, 0); break; default: //std::printf("Unexpected symbol %c at (%d, %d)", tile, x, y); break; } } } spriteBatch.end(); } // Dont need this anymore charLevelFile[0].clear(); charLevelFile[1].clear(); }
void TextSprite::Update(const AbstractTextDrawer& drawer) { CallOnExit clearOnFail([this]() { Clear(); }); // Mark every atlas as unused... for (auto& pair : m_atlases) pair.second.used = false; // ... until they are marked as used by the drawer std::size_t fontCount = drawer.GetFontCount(); for (std::size_t i = 0; i < fontCount; ++i) { Font* font = drawer.GetFont(i); const AbstractAtlas* atlas = font->GetAtlas().get(); NazaraAssert(atlas->GetStorage() & DataStorage_Hardware, "Font uses a non-hardware atlas which cannot be used by text sprites"); auto it = m_atlases.find(atlas); if (it == m_atlases.end()) { it = m_atlases.insert(std::make_pair(atlas, AtlasSlots())).first; AtlasSlots& atlasSlots = it->second; atlasSlots.clearSlot.Connect(atlas->OnAtlasCleared, this, &TextSprite::OnAtlasInvalidated); atlasSlots.layerChangeSlot.Connect(atlas->OnAtlasLayerChange, this, &TextSprite::OnAtlasLayerChange); atlasSlots.releaseSlot.Connect(atlas->OnAtlasRelease, this, &TextSprite::OnAtlasInvalidated); } it->second.used = true; } // Remove unused atlas slots auto atlasIt = m_atlases.begin(); while (atlasIt != m_atlases.end()) { if (!atlasIt->second.used) m_atlases.erase(atlasIt++); else ++atlasIt; } std::size_t glyphCount = drawer.GetGlyphCount(); m_localVertices.resize(glyphCount * 4); // Reset glyph count for every texture to zero for (auto& pair : m_renderInfos) pair.second.count = 0; // Count glyph count for each texture Texture* lastTexture = nullptr; unsigned int* count = nullptr; for (std::size_t i = 0; i < glyphCount; ++i) { const AbstractTextDrawer::Glyph& glyph = drawer.GetGlyph(i); Texture* texture = static_cast<Texture*>(glyph.atlas); if (lastTexture != texture) { auto it = m_renderInfos.find(texture); if (it == m_renderInfos.end()) it = m_renderInfos.insert(std::make_pair(texture, RenderIndices{0U, 0U})).first; count = &it->second.count; lastTexture = texture; } (*count)++; } // Attributes indices and reinitialize glyph count to zero to use it as a counter in the next loop // This is because the 1st glyph can use texture A, the 2nd glyph can use texture B and the 3th glyph C can use texture A again // so we need a counter to know where to write informations // also remove unused render infos unsigned int index = 0; auto infoIt = m_renderInfos.begin(); while (infoIt != m_renderInfos.end()) { RenderIndices& indices = infoIt->second; if (indices.count == 0) m_renderInfos.erase(infoIt++); //< No glyph uses this texture, remove from indices else { indices.first = index; index += indices.count; indices.count = 0; ++infoIt; } } lastTexture = nullptr; RenderIndices* indices = nullptr; for (unsigned int i = 0; i < glyphCount; ++i) { const AbstractTextDrawer::Glyph& glyph = drawer.GetGlyph(i); Texture* texture = static_cast<Texture*>(glyph.atlas); if (lastTexture != texture) { indices = &m_renderInfos[texture]; //< We changed texture, adjust the pointer lastTexture = texture; } // First, compute the uv coordinates from our atlas rect Vector2ui size(texture->GetSize()); float invWidth = 1.f / size.x; float invHeight = 1.f / size.y; Rectf uvRect(glyph.atlasRect); uvRect.x *= invWidth; uvRect.y *= invHeight; uvRect.width *= invWidth; uvRect.height *= invHeight; // Our glyph may be flipped in the atlas, to render it correctly we need to change the uv coordinates accordingly const RectCorner normalCorners[4] = {RectCorner_LeftTop, RectCorner_RightTop, RectCorner_LeftBottom, RectCorner_RightBottom}; const RectCorner flippedCorners[4] = {RectCorner_LeftBottom, RectCorner_LeftTop, RectCorner_RightBottom, RectCorner_RightTop}; // Set the position, color and UV of our vertices for (unsigned int j = 0; j < 4; ++j) { // Remember that indices->count is a counter here, not a count value m_localVertices[indices->count * 4 + j].color = glyph.color; m_localVertices[indices->count * 4 + j].position.Set(glyph.corners[j]); m_localVertices[indices->count * 4 + j].uv.Set(uvRect.GetCorner((glyph.flipped) ? flippedCorners[j] : normalCorners[j])); } // Increment the counter, go to next glyph indices->count++; } m_localBounds = drawer.GetBounds(); InvalidateBoundingVolume(); InvalidateInstanceData(0); clearOnFail.Reset(); }
Level::Level(const std::string &fileName) { // open the file std::ifstream file; file.open(fileName); // error checking if (file.fail()) { CoreEngine::fatalError("Failed to open " + fileName); } // reads the first string of the file ("humans:") to tmp and ignore it; // save the number of humans that comes after to the variable _numHumans std::string tmp; file >> tmp >> _numHumans; std::getline(file, tmp); //throw away the rest of the first line //read the level data while (std::getline(file, tmp)) { _levelData.push_back(tmp); } _spriteBatch.init(); _spriteBatch.begin(); glm::vec4 uvRect(0.0f, 0.0f, 1.0f, 1.0f); CoreEngine::ColorRGBA8 whiteColor = CoreEngine::ColorRGBA8(255, 255, 255, 255); //render all the tiles for (int y = 0; y < _levelData.size(); y++) { for (int x = 0; x < _levelData[y].size(); x++) { char tile = _levelData[y][x]; //get dest rect glm::vec4 destRect(x * TILE_WIDTH, y * TILE_WIDTH, TILE_WIDTH, TILE_WIDTH); //process each tile switch (tile) { case '.': break; case 'B': case 'R': _spriteBatch.draw(destRect, uvRect, CoreEngine::ResourceManager::getTexture("Textures/red_bricks.png").id, 0.0f, whiteColor); break; case 'G': _spriteBatch.draw(destRect, uvRect, CoreEngine::ResourceManager::getTexture("Textures/glass.png").id, 0.0f, whiteColor); break; case 'L': _spriteBatch.draw(destRect, uvRect, CoreEngine::ResourceManager::getTexture("Textures/light_bricks.png").id, 0.0f, whiteColor); break; case '@': _levelData[y][x] = '.'; ///setting the tile back to normal and we don't collide with those _startPlayerPos.x = x * TILE_WIDTH; _startPlayerPos.y = y * TILE_WIDTH; break; case 'Z': _levelData[y][x] = '.'; ///setting the tile back to normal and we don't collide with those _zombiesStartPos.emplace_back(x * TILE_WIDTH, y * TILE_WIDTH); // allows to use constructor arguments with the function call break; default: std::printf("Unexpected symbol %c at (%d, %d)", tile, x, y); break; } } } _spriteBatch.end(); }
Level::Level(const std::string& fileName) { std::ifstream file; file.open(fileName); if(file.fail()) Engine::fatalError("Failed to open " + fileName); //throw away the first string in tmp std::string tmp; file >> tmp >> _numHumans; std::getline(file, tmp); //throw away the rest of the first line //read level data while(std::getline(file, tmp)) _levelData.push_back(tmp); _spriteBatch.init(); _spriteBatch.begin(); //texture coordinates rect glm::vec4 uvRect(0.0f, 0.0f, 1.0f, 1.0f); Engine::Color whiteColor; whiteColor.r = 255; whiteColor.g = 255; whiteColor.b = 255; whiteColor.a = 255; //render all the tiles for(int y = 0; y < _levelData.size(); ++y) { for(int x = 0; x < _levelData[y].size(); ++x) { //grab the tile char tile = _levelData[y][x]; //get the destination rect glm::vec4 destRect(x * TILE_WIDTH, y * TILE_WIDTH, TILE_WIDTH, TILE_WIDTH); //process the tile - what color is it? switch(tile) { case 'B': case 'R': _spriteBatch.draw(destRect, uvRect, Engine::ResourceManager::getTexture("../../game/Textures/red_bricks.png").id, 0.0f, whiteColor); break; case 'G': _spriteBatch.draw(destRect, uvRect, Engine::ResourceManager::getTexture("../../game/Textures/glass.png").id, 0.0f, whiteColor); break; case 'L': _spriteBatch.draw(destRect, uvRect, Engine::ResourceManager::getTexture("../../game/Textures/light_bricks.png").id, 0.0f, whiteColor); break; case '@': _levelData[y][x] = '.'; //don't collide with an @ _startPlayerPos.x = x * TILE_WIDTH; _startPlayerPos.y = y * TILE_WIDTH; break; case 'Z': _levelData[y][x] = '.'; //so we don't collide with a Z _zombieStartPositions.emplace_back(x * TILE_WIDTH, y * TILE_WIDTH); break; case '.': break; default: std::printf("Unexpected symbol %c at (%d, %d)", tile, x, y); break; } } } _spriteBatch.end(); }