Store Fl:Button value from callback (FLTK) - c++

I am trying to write a program that simulates a chess game with the FLTK library.
My problem is that I want to do two callbacks on an two dimension array of buttons, I want to click a button, then click another button and when the second button is clicked have the label of the first button switch to the label of the second button and then delete the label of the first button.
I feel like I need someway of storing the value of the the first button that is clicked, for example if I click FBoard[1][2] the i have a variable that is equal to FBoard[1][2] and open the second click replace the label of FBoard[1][2] to blank (assuming FBoard[1][2] is a cell on the board that has a piece on it. But I'm not sure how or even if this is the right approach.
Here is the cpp file:
#include"Window.h"
#include"ChessBoard.h"
const char * DisplayWindow::LastLabel;
bool DisplayWindow::flag;
DisplayWindow::DisplayWindow(int width, int height, const char*)
:Fl_Window(800, 650, "Chess"){
for (int X = 0; X <= 7; ++X){
for (int Y = 0; Y <= 7; ++Y){
// Leaves all positions that arent occupied by
// a figure at the start of the game blank
FBoard[X][Y] = new Fl_Button(10 + 50*Y, 100 + 50*X, 50, 50,"");
FBoard[X][Y]->callback((Fl_Callback*)DisplayWindow::ChangeButton);
}
}
flag = false;
MakeLabel();
LabelButton();
show();
}
DisplayWindow::~DisplayWindow(){}
void DisplayWindow::MakeLabel(){
for (int X = 0; X <= 7; ++X){
for (int Y = 0; Y <= 7; ++Y){
LBoard[X][Y] = (" ");
}
}
for (int X = 0; X <= 7; ++X){
LBoard[1][X] = ("WP");
// Occupies second row with white pawns
}
LBoard[0][0] = ("WR");
LBoard[0][1] = ("WH");
LBoard[0][2] = ("WB");
LBoard[0][3] = ("WQ");
LBoard[0][4] = ("WK");
LBoard[0][5] = ("WB");
LBoard[0][6] = ("WH");
LBoard[0][7] = ("WR");
for (int X = 0; X <= 7; ++X){
LBoard[6][X] = ("BP");
}
LBoard[7][0] = ("BR");
LBoard[7][1] = ("BH");
LBoard[7][2] = ("BB");
LBoard[7][3] = ("BQ");
LBoard[7][4] = ("BK");
LBoard[7][5] = ("BB");
LBoard[7][6] = ("BH");
LBoard[7][7] = ("BR");
}
void DisplayWindow::LabelButton(){
for (int X = 0; X <= 7; ++X){
FBoard[1][X]->label(LBoard[1][X]);
// Occupies second row with white pawns
}
FBoard[0][0]->label(LBoard[0][0]);
FBoard[0][1]->label(LBoard[0][1]);
FBoard[0][2]->label(LBoard[0][2]);
FBoard[0][3]->label(LBoard[0][3]);
FBoard[0][4]->label(LBoard[0][4]);
FBoard[0][5]->label(LBoard[0][5]);
FBoard[0][6]->label(LBoard[0][6]);
FBoard[0][7]->label(LBoard[0][7]);
for (int X = 0; X <= 7; ++X){
FBoard[6][X]->label(LBoard[6][X]);
}
FBoard[7][0] ->label(LBoard[7][0]);
FBoard[7][1] ->label(LBoard[7][1]);
FBoard[7][2] ->label(LBoard[7][2]);
FBoard[7][3] ->label(LBoard[7][3]);
FBoard[7][4] ->label(LBoard[7][4]);
FBoard[7][5] ->label(LBoard[7][5]);
FBoard[7][6] ->label(LBoard[7][6]);
FBoard[7][7] ->label(LBoard[7][7]);
for(int i=0 ; i<=7 ; i++)
{
for(int j=0 ; j<=7 ; j++)
{
int k=i+j;
if(k % 2 != 0 ){
FBoard[i][j]->color(FL_WHITE);
}
else if (k % 2 ==0 ){
FBoard[i][j]->color(FL_YELLOW);
}
}
}
}
void DisplayWindow::ChangeButton(Fl_Widget * o, void * v){
DisplayWindow* Win = (DisplayWindow *) v;
Fl_Button * NewBoard = (Fl_Button*) o;
if (Win->flag == false){
DisplayWindow::LastLabel = NewBoard->label();
NewBoard->label(" ");
Win->flag = true;
}
else{
NewBoard->label(DisplayWindow::LastLabel);
Win->flag = false;
}
}
And the Header file:
class DisplayWindow: public Fl_Window {
public:
DisplayWindow(int width, int height, const char* title=0);
virtual ~DisplayWindow();
void MakeLabel();
void LabelButton();
static void ChangeButton(Fl_Button * o, void * );
static bool flag;
bool flag1;
static const char * LastLabel;
private:
Fl_Button * FBoard[8][8];
char * LBoard[8][8];
};
#endif

cpp:
#include"Window.h"
#include"ChessBoard.h"
const char * DisplayWindow::LastLabel;
bool DisplayWindow::flag;
DisplayWindow::DisplayWindow(int width, int height, const char*)
:Fl_Window(800, 650, "Chess"){
for (int X = 0; X <= 7; ++X){
for (int Y = 0; Y <= 7; ++Y){
// Leaves all positions that arent occupied by
// a figure at the start of the game blank
FBoard[X][Y] = new Fl_Button(10 + 50*Y, 100 + 50*X, 50, 50,"");
FBoard[X][Y]->callback((Fl_Callback*)DisplayWindow::ChangeButton);
//FBoard[X][Y]->callback(ChangeButton);
}
}
flag = false;
MakeLabel();
LabelButton();
show();
}
DisplayWindow::~DisplayWindow(){}
void DisplayWindow::MakeLabel(){
for (int X = 0; X <= 7; ++X){
for (int Y = 0; Y <= 7; ++Y){
LBoard[X][Y] = (" ");
}
}
for (int X = 0; X <= 7; ++X){
LBoard[1][X] = ("WP");
// Occupies second row with white pawns
}
LBoard[0][0] = ("WR");
LBoard[0][1] = ("WH");
LBoard[0][2] = ("WB");
LBoard[0][3] = ("WQ");
LBoard[0][4] = ("WK");
LBoard[0][5] = ("WB");
LBoard[0][6] = ("WH");
LBoard[0][7] = ("WR");
for (int X = 0; X <= 7; ++X){
LBoard[6][X] = ("BP");
}
LBoard[7][0] = ("BR");
LBoard[7][1] = ("BH");
LBoard[7][2] = ("BB");
LBoard[7][3] = ("BQ");
LBoard[7][4] = ("BK");
LBoard[7][5] = ("BB");
LBoard[7][6] = ("BH");
LBoard[7][7] = ("BR");
}
void DisplayWindow::LabelButton(){
for (int X = 0; X <= 7; ++X){
FBoard[1][X]->label(LBoard[1][X]);
// Occupies second row with white pawns
}
FBoard[0][0]->label(LBoard[0][0]);
FBoard[0][1]->label(LBoard[0][1]);
FBoard[0][2]->label(LBoard[0][2]);
FBoard[0][3]->label(LBoard[0][3]);
FBoard[0][4]->label(LBoard[0][4]);
FBoard[0][5]->label(LBoard[0][5]);
FBoard[0][6]->label(LBoard[0][6]);
FBoard[0][7]->label(LBoard[0][7]);
for (int X = 0; X <= 7; ++X){
FBoard[6][X]->label(LBoard[6][X]);
}
FBoard[7][0] ->label(LBoard[7][0]);
FBoard[7][1] ->label(LBoard[7][1]);
FBoard[7][2] ->label(LBoard[7][2]);
FBoard[7][3] ->label(LBoard[7][3]);
FBoard[7][4] ->label(LBoard[7][4]);
FBoard[7][5] ->label(LBoard[7][5]);
FBoard[7][6] ->label(LBoard[7][6]);
FBoard[7][7] ->label(LBoard[7][7]);
for(int i=0 ; i<=7 ; i++)
{
for(int j=0 ; j<=7 ; j++)
{
int k=i+j;
if(k % 2 != 0 ){
FBoard[i][j]->color(FL_WHITE);
}
else if (k % 2 ==0 ){
FBoard[i][j]->color(FL_YELLOW);
}
}
}
}
void DisplayWindow::ChangeButton(Fl_Widget * o, void * v){
DisplayWindow* Win = (DisplayWindow *) v;
Fl_Button * NewBoard = (Fl_Button*) o;
if (Win->flag == false){
DisplayWindow::LastLabel = NewBoard->label();
NewBoard->label(" ");
Win->flag = true;
}
else{
NewBoard->label(DisplayWindow::LastLabel);
Win->flag = false;
}
}
h:
#ifndef WINDOW_H_
#define WINDOW_H_
#include<vector>
#include<limits>
#include<string>
#include<iostream>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
class DisplayWindow: public Fl_Window {
public:
DisplayWindow(int width, int height, const char* title=0);
virtual ~DisplayWindow();
void MakeLabel();
void LabelButton();
static void ChangeButton(Fl_Widget * o, void * );
static bool flag;
bool flag1;
static const char * LastLabel;
private:
Fl_Button * FBoard[8][8];
char * LBoard[8][8];
};
#endif

Related

Creating a nested for loop clipping function

My old C++ code reads a spritesheet (rows = different buttons, cols = different button states) one row at a time using for loops and divides them into individual sprite clips. All the sprites are the same size. Works fine.
Now, I want to put the elements of the clipping for loops into a struct so that I can write a single clipping function to iterate through every graphic on a given spritesheet. Running into a few problems getting everything to work. Something changed with the enums when I put them in the struct, and I think I screwed up the nested for loop.
Old Code
const int LONGBUTTON_HEIGHT = 128;
const int LONGBUTTON_WIDTH = 256;
enum CreateButtonState { CREATE_DEFAULT, CREATE_HOVER, CREATE_PRESSED, CREATE_TOTAL };
enum CreditsButtonState { CREDITS_DEFAULT, CREDITS_HOVER, CREDITS_PRESSED, CREDITS_TOTAL };
enum MenuButtonState { MENU_DEFAULT, MENU_HOVER, MENU_PRESSED, MENU_TOTAL };
main
{
//Load long button spritesheet texture
SDL_Texture* longbutton_image = loadTexture("longbuttonSpriteSheet.png", renderer);
//Long Buttons
//Create Button Setup
SDL_Rect create_clips[CreateButtonState::CREATE_TOTAL];
for (int i = 0; i < CreateButtonState::CREATE_TOTAL; i++)
{
create_clips[i].x = i * LONGBUTTON_WIDTH;
create_clips[i].y = 0;
create_clips[i].w = LONGBUTTON_WIDTH;
create_clips[i].h = LONGBUTTON_HEIGHT;
}
int useCreate_Clip = CREATE_DEFAULT;
// Credits Button Setup
SDL_Rect credits_clips[CreditsButtonState::CREDITS_TOTAL];
for (int i = 0; i < CreditsButtonState::CREDITS_TOTAL; i++)
{
credits_clips[i].x = i * LONGBUTTON_WIDTH;
credits_clips[i].y = 1 * LONGBUTTON_HEIGHT;
credits_clips[i].w = LONGBUTTON_WIDTH;
credits_clips[i].h = LONGBUTTON_HEIGHT;
}
int useCredits_Clip = CREDITS_DEFAULT;
//Menu Button Setup
SDL_Rect menu_clips[MenuButtonState::MENU_TOTAL];
for (int i = 0; i < MenuButtonState::MENU_TOTAL; i++)
{
menu_clips[i].x = i * LONGBUTTON_WIDTH;
menu_clips[i].y = 2 * LONGBUTTON_HEIGHT;
menu_clips[i].w = LONGBUTTON_WIDTH;
menu_clips[i].h = LONGBUTTON_HEIGHT;
}
int useMenu_Clip = MENU_DEFAULT;
return 0;
}
New Code
int originalspriteH = 128;
int originalspriteW = 256;
int spritesheetcols = 2;
struct Graphic
{
typedef enum buttonstate {DEFAULT, HOVER, PRESSED, TOTAL};
SDL_Rect clip;
int useClip;
};
void clipSprites(int spritesheetcols, int originalspriteH, int originalspriteW, [Graphic &graphic])
{
for (int j =0; j < spritesheetcols; j++)
{
graphic.clip[graphic.buttonstate::TOTAL];
}
for (int i = 0, i < graphic.buttonstate::TOTAL; i++)
{
graphic.clip[i].x = i * originalspriteW;
graphic.clip[i].y = j * originalspriteH;
graphic.clip[i].h = originalspriteW;
graphic.clip[i].w = originalspriteH;
}
graphic.useClip = DEFAULT;
}
main
{
clipSprites(2, 128, 256, [create, credits, menu])
return 0;
}

Creating an X amount of rectangles which are not intersecting each other on a specified screen size

I managed with some help to know how when two rectangles are intersecting each other, from there it should be easy to make what i just said in the title but ...
So, short story of what i just did below:
Created a for loop from 1 to Number_of_Obstacles
In that for an random obstacle (rectangle/square) is created and it will be checked if it is overlaped with all other obstacles created from 0 to the loop contor (or in other words every obstacle stored in the vector)
Again, the doOverLap function works. Tested it with a square which i made a controller and other random rectangle created on the screen. It outputs in chat when i'm overlaping it and trust me, i overlaped it from all angles.
Here is a picture with the overlaping issue: https://imgur.com/a/ZzorOcD
bool doOverlap(A a, B b)
{
if (a.x1 > b.x2 || b.x1 > a.x2)
return false;
if (a.y1 > b.y2 || b.y1 > a.y2)
return false;
return true;
}
struct Obstacles {
int X, Y;
void Create_Random_Obstacles(Obstacles Obj[], int Numar_Obstacole)
{
srand(time(NULL));
A Rectangle_1;
B Rectangle_2;
/* To avoid rendering outside of the screen */
int X_Axis = X_RESOLUTION - 40;
int Y_Axis = Y_RESOLUTION - 40;
int obstacolX = rand() % X_Axis + 1;
int obstacolY = rand() % Y_Axis + 1;
Obj[0].X = obstacolX;
Obj[0].Y = obstacolY;
for (int i = 1; i < Numar_Obstacole; i++)
{
obstacolX = rand() % X_Axis + 1;
obstacolY = rand() % Y_Axis + 1;
Rectangle_1.x1 = obstacolX;
Rectangle_1.x2 = obstacolX + 40;
Rectangle_1.y1 = obstacolY;
Rectangle_1.y2 = obstacolY + 40;
for (int j = 0; j < i; j++) {
Rectangle_2.x1 = Obj[j].X;
Rectangle_2.x2 = Obj[j].X + 40;
Rectangle_2.y1 = Obj[j].Y;
Rectangle_2.y2 = Obj[j].Y + 40;
if (doOverlap(Rectangle_1, Rectangle_2))
{
std::cout << "Overlap\n";
}
else
{
Obj[i].X = obstacolX;
Obj[i].Y = obstacolY;
}
}
}
}
void Render(SDL_Renderer* renderer, Obstacles Obj[], int Numar_Obstacole) {
for (int i = 0; i < Numar_Obstacole; i++)
{
SDL_Rect r{ Obj[i].X, Obj[i].Y, 40, 40 };
SDL_SetRenderDrawColor(renderer, 255, 160, 15, 255);
SDL_RenderFillRect(renderer, &r);
}
}
};
Restart selection when collision occurs, something like:
bool Has_Overlap(const Obstacles& obj, const Obstacles* Objs, int Size)
{
B Rectangle_2;
Rectangle_2.x1 = obs.X;
Rectangle_2.x2 = obs.X + 40;
Rectangle_2.y1 = obs.Y;
Rectangle_2.y2 = obs.Y + 40;
for (int i = 0; i != Size; ++i) {
A Rectangle_1;
Rectangle_1.x1 = Obs[i].X;
Rectangle_1.x2 = Obs[i].X + 40;
Rectangle_1.y1 = Obs[i].Y;
Rectangle_1.y2 = Obs[i].Y + 40;
if (doOverlap(Rectangle_1, Rectangle_2)) {
return true;
}
}
return false;
}
void Create_Random_Obstacles(Obstacles* Objs, int Size)
{
/* To avoid rendering outside of the screen */
const int X_Axis = X_RESOLUTION - 40;
const int Y_Axis = Y_RESOLUTION - 40;
for (int i = 0; i < Size; i++)
{
do {
Objs[i].X = rand() % X_Axis + 1;
Objs[i].Y = rand() % Y_Axis + 1;
} while (Has_Overlap(Objs[i], Objs, i));
}
}

VS Express dosen't compile the code properly (?) [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
So I used to use Code::Blocks IDE, and like it a lot. Recently I switched to Visual Studio. I downloaded VS Express, it was 600mb and I can only use 1gb data per day, I don't have Wi-Fi, so I that was my only option.I inserted the same code that compiled properly in Code::Blocks in it , it took a few tweaks to make it work in VS, but when I finally check it, the output was totally different, Instead of a command line Tetris, it glitched and filled the command prompt with strange characters.
This is the code I tweaked a bit to make it work in VS:
#include <iostream>
#include <time.h>
#include <string>
#include <windows.h>
using namespace std;
int nScreenHeight = 30;
int nScreenWidth = 80;
int nFieldWidth = 10;
int nFieldHeight = 25;
unsigned char *pField = NULL;
wstring tetromine[7];
int currentPiece = 0;
int currentRotation = 0;
int currentX = (nFieldWidth/2);
int currentY = 0;
unsigned int score = 0;
int pieceCounter = 0;
int speed = 20;
int speedCounter = 0;
bool forcePieceDown =false;
bool key[4];
bool shiftGridDown = false;
int rotate(int px,int py,int r)
{
switch(r/90)
{
case 0:
return py*4+px;//0 degs
case 1:
return 12+py - (px*4);//90 degs
case 2:
return 15 - (py*4) - px;//180 degs
case 3:
return 3 - py + (px*4);//270 degs
}
return 0;
}
int doesPieceFit(int id,int rot, int x, int y)
{
for(int px = 0;px<4;px++){
for(int py = 0;py<4;py++){
int pi = rotate(px,py,rot);
int fi = (y+py) * nFieldWidth + (x+px);
if(x + px>= 0 && x+px < nFieldWidth){
if(tetromine[id][pi] == L'X' && pField[fi]!=0){
return false;
}
}
}
}
return true;
}
void lineCheck(){
bool line = true;
int lines = 0;
for(int y = 0; y<= nFieldHeight-1;y++){
for(int x = 1; x< nFieldWidth-1;x++){
if(pField[(y)*nFieldWidth+x]!=0){
line &= true;
} else line &= false;
}
if(line) lines++;
if(line){
for(int x = 1; x< nFieldWidth-1;x++){
pField[(y)*nFieldWidth+x] = 8;
}
}
}
}
int main()
{
//assets
tetromine[0].append(L"..X.");
tetromine[0].append(L"..X.");
tetromine[0].append(L"..X.");
tetromine[0].append(L"..X.");
tetromine[1].append(L"..X.");
tetromine[1].append(L".XX.");
tetromine[1].append(L".X..");
tetromine[1].append(L"....");
tetromine[2].append(L".X..");
tetromine[2].append(L".XX.");
tetromine[2].append(L"..X.");
tetromine[2].append(L"....");
tetromine[3].append(L"....");
tetromine[3].append(L".XX.");
tetromine[3].append(L".XX.");
tetromine[3].append(L"....");
tetromine[4].append(L"..X.");
tetromine[4].append(L".XX.");
tetromine[4].append(L"..X.");
tetromine[4].append(L"....");
tetromine[5].append(L"....");
tetromine[5].append(L".XX.");
tetromine[5].append(L"..X.");
tetromine[5].append(L"..X.");
tetromine[6].append(L"....");
tetromine[6].append(L".XX.");
tetromine[6].append(L".X..");
tetromine[6].append(L".X..");
pField = new unsigned char[nFieldWidth*nFieldHeight];
for(int x = 0; x<nFieldWidth; x++)
{
for(int y = 0; y<nFieldHeight; y++)
{
pField[y*nFieldWidth + x] = (x==0||x==nFieldWidth -1 || y == nFieldHeight - 1) ? 9 : 0;
}
}
char *screen = new char [nScreenWidth * nScreenHeight];
HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
SetConsoleActiveScreenBuffer(hConsole);
DWORD dwBytesWritten = 0;
//Display frame
COORD here;
here.X = 0;
here.Y = 0;
WriteConsoleOutputCharacter(hConsole, (LPCWSTR)screen, nScreenWidth * nScreenHeight,here, &dwBytesWritten);
bool gameOver = false;
while(!gameOver)
{
Sleep(100);
speedCounter++;
if(speedCounter>=speed){
forcePieceDown = true;
speedCounter = 0;
} else {
forcePieceDown = false;
}
if(shiftGridDown){
score++;
for(int y = nFieldHeight-2;y > 0;y--){
for(int x = 1;x<nFieldWidth -1;x++){
if((pField[(y)*nFieldWidth+x]) != 0){
pField[(y+1)*nFieldWidth+x] = pField[(y)*nFieldWidth+x];
pField[(y)*nFieldWidth+x] = 0;
}
}
}
shiftGridDown = false;
lineCheck();
}
for(int x = 1; x< nFieldWidth-1;x++){
if(pField[(nFieldHeight-2)*nFieldWidth+x]==8){
pField[(nFieldHeight-2)*nFieldWidth+x]=0;
if(x==nFieldWidth-2){
shiftGridDown = true;
score+=100;
}
}
}
for(int k = 0;k<4;k++){ // R L D Z
key[k] = (0x8000 & GetAsyncKeyState((unsigned char)("DASZ"[k]))) != 0;
}
if(key[1]){
if(doesPieceFit(currentPiece,currentRotation,currentX-1,currentY)){
currentX = currentX-1;
}
}else if(key[0]){
if(doesPieceFit(currentPiece,currentRotation,currentX+1,currentY)){
currentX = currentX+1;
}
}if(key[2]){
speedCounter = speed;
}
if(key[3]&&doesPieceFit(currentPiece,currentRotation+90,currentX,currentY)){
(currentRotation+90<=270)?currentRotation+=90:currentRotation=0;
}
if(forcePieceDown){
if(doesPieceFit(currentPiece,currentRotation,currentX,currentY+1))
currentY++;
else {
//lock piece
pieceCounter++;
if(pieceCounter%5==0){
speed-=1;
}
for(int px = 0;px<4;px++){
for(int py = 0;py<4;py++){
if(tetromine[currentPiece][rotate(px,py,currentRotation)]==L'X'){
pField[(currentY+py)*nFieldWidth+(currentX+px)] = currentPiece+1;
}
}
}
score+=20;
//check lines
lineCheck();
//get next piece
currentX = nFieldWidth/2;
currentY = 0;
currentRotation = 0;
srand(time(0));
currentPiece = rand() % 7;
//check game over
gameOver = !doesPieceFit(currentPiece,currentRotation,currentX,currentY);
}
}
//draw field
for(int x = 0; x < nFieldWidth; x++)
{
for(int y = 0; y < nFieldHeight; y++)
{
screen[(y+2)*nScreenWidth + (x+ 2)] = L" xxxxxxx=#"[pField[y*nFieldWidth + x]];
}
}
//draw piece
for(int px = 0;px<4;px++){
for(int py = 0;py<4;py++){
if(tetromine[currentPiece][rotate(px,py,currentRotation)] == L'X'){
screen[(currentY+py+2)*nScreenWidth+(currentX+px+2)] = '+';
}
}
}
string s("Score -> ");
string num;
int tmp = score;
while(tmp!=0){
int rem = tmp%10;
tmp /= 10;
num = ((char)(48+rem)) + num;
}
s+=num;
for(int i = 0; i<s.size();i++){
screen[i] = s[i];
}
//display frame
WriteConsoleOutputCharacter(hConsole, (LPCWSTR)screen, nScreenWidth * nScreenHeight,here, &dwBytesWritten);
}
return 0;
}
This is the origional code :
#include <iostream>
#include <time.h>
#include <string>
#include <windows.h>
using namespace std;
int nScreenHeight = 30;
int nScreenWidth = 80;
int nFieldWidth = 10;
int nFieldHeight = 25;
unsigned char *pField = NULL;
wstring tetromine[7];
int currentPiece = 0;
int currentRotation = 0;
int currentX = (nFieldWidth/2);
int currentY = 0;
unsigned int score = 0;
int pieceCounter = 0;
int speed = 20;
int speedCounter = 0;
bool forcePieceDown =false;
bool key[4];
bool shiftGridDown = false;
int rotate(int px,int py,int r)
{
switch(r/90)
{
case 0:
return py*4+px;//0 degs
case 1:
return 12+py - (px*4);//90 degs
case 2:
return 15 - (py*4) - px;//180 degs
case 3:
return 3 - py + (px*4);//270 degs
}
return 0;
}
int doesPieceFit(int id,int rot, int x, int y)
{
for(int px = 0;px<4;px++){
for(int py = 0;py<4;py++){
int pi = rotate(px,py,rot);
int fi = (y+py) * nFieldWidth + (x+px);
if(x + px>= 0 && x+px < nFieldWidth){
if(tetromine[id][pi] == L'X' && pField[fi]!=0){
return false;
}
}
}
}
return true;
}
void lineCheck(){
bool line = true;
int lines = 0;
for(int y = 0; y<= nFieldHeight-1;y++){
for(int x = 1; x< nFieldWidth-1;x++){
if(pField[(y)*nFieldWidth+x]!=0){
line &= true;
} else line &= false;
}
if(line) lines++;
if(line){
for(int x = 1; x< nFieldWidth-1;x++){
pField[(y)*nFieldWidth+x] = 8;
}
}
}
}
int main()
{
//assets
tetromine[0].append(L"..X.");
tetromine[0].append(L"..X.");
tetromine[0].append(L"..X.");
tetromine[0].append(L"..X.");
tetromine[1].append(L"..X.");
tetromine[1].append(L".XX.");
tetromine[1].append(L".X..");
tetromine[1].append(L"....");
tetromine[2].append(L".X..");
tetromine[2].append(L".XX.");
tetromine[2].append(L"..X.");
tetromine[2].append(L"....");
tetromine[3].append(L"....");
tetromine[3].append(L".XX.");
tetromine[3].append(L".XX.");
tetromine[3].append(L"....");
tetromine[4].append(L"..X.");
tetromine[4].append(L".XX.");
tetromine[4].append(L"..X.");
tetromine[4].append(L"....");
tetromine[5].append(L"....");
tetromine[5].append(L".XX.");
tetromine[5].append(L"..X.");
tetromine[5].append(L"..X.");
tetromine[6].append(L"....");
tetromine[6].append(L".XX.");
tetromine[6].append(L".X..");
tetromine[6].append(L".X..");
pField = new unsigned char[nFieldWidth*nFieldHeight];
for(int x = 0; x<nFieldWidth; x++)
{
for(int y = 0; y<nFieldHeight; y++)
{
pField[y*nFieldWidth + x] = (x==0||x==nFieldWidth -1 || y == nFieldHeight - 1) ? 9 : 0;
}
}
char *screen = new char [nScreenWidth * nScreenHeight];
HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
SetConsoleActiveScreenBuffer(hConsole);
DWORD dwBytesWritten = 0;
//Display frame
WriteConsoleOutputCharacter(hConsole, screen, nScreenWidth * nScreenHeight, {0,0}, &dwBytesWritten);
bool gameOver = false;
while(!gameOver)
{
Sleep(100);
speedCounter++;
if(speedCounter>=speed){
forcePieceDown = true;
speedCounter = 0;
} else {
forcePieceDown = false;
}
if(shiftGridDown){
score++;
for(int y = nFieldHeight-2;y > 0;y--){
for(int x = 1;x<nFieldWidth -1;x++){
if((pField[(y)*nFieldWidth+x]) != 0){
pField[(y+1)*nFieldWidth+x] = pField[(y)*nFieldWidth+x];
pField[(y)*nFieldWidth+x] = 0;
}
}
}
shiftGridDown = false;
lineCheck();
}
for(int x = 1; x< nFieldWidth-1;x++){
if(pField[(nFieldHeight-2)*nFieldWidth+x]==8){
pField[(nFieldHeight-2)*nFieldWidth+x]=0;
if(x==nFieldWidth-2){
shiftGridDown = true;
score+=100;
}
}
}
for(int k = 0;k<4;k++){ // R L D Z
key[k] = (0x8000 & GetAsyncKeyState((unsigned char)("DASZ"[k]))) != 0;
}
if(key[1]){
if(doesPieceFit(currentPiece,currentRotation,currentX-1,currentY)){
currentX = currentX-1;
}
}else if(key[0]){
if(doesPieceFit(currentPiece,currentRotation,currentX+1,currentY)){
currentX = currentX+1;
}
}if(key[2]){
speedCounter = speed;
}
if(key[3]&&doesPieceFit(currentPiece,currentRotation+90,currentX,currentY)){
(currentRotation+90<=270)?currentRotation+=90:currentRotation=0;
}
if(forcePieceDown){
if(doesPieceFit(currentPiece,currentRotation,currentX,currentY+1))
currentY++;
else {
//lock piece
pieceCounter++;
if(pieceCounter%5==0){
speed-=1;
}
for(int px = 0;px<4;px++){
for(int py = 0;py<4;py++){
if(tetromine[currentPiece][rotate(px,py,currentRotation)]==L'X'){
pField[(currentY+py)*nFieldWidth+(currentX+px)] = currentPiece+1;
}
}
}
score+=20;
//check lines
lineCheck();
//get next piece
currentX = nFieldWidth/2;
currentY = 0;
currentRotation = 0;
srand(time(0));
currentPiece = rand() % 7;
//check game over
gameOver = !doesPieceFit(currentPiece,currentRotation,currentX,currentY);
}
}
//draw field
for(int x = 0; x < nFieldWidth; x++)
{
for(int y = 0; y < nFieldHeight; y++)
{
screen[(y+2)*nScreenWidth + (x+ 2)] = L" xxxxxxx=#"[pField[y*nFieldWidth + x]];
}
}
//draw piece
for(int px = 0;px<4;px++){
for(int py = 0;py<4;py++){
if(tetromine[currentPiece][rotate(px,py,currentRotation)] == L'X'){
screen[(currentY+py+2)*nScreenWidth+(currentX+px+2)] = '+';
}
}
}
string s("Score -> ");
string num;
int tmp = score;
while(tmp!=0){
int rem = tmp%10;
tmp /= 10;
num = ((char)(48+rem)) + num;
}
s+=num;
for(int i = 0; i<s.size();i++){
screen[i] = s[i];
}
//display frame
WriteConsoleOutputCharacter(hConsole, screen, nScreenWidth * nScreenHeight, { 0, 0}, &dwBytesWritten);
}
return 0;
}
You have a mix of narrow and wide characters. The cast (LPCWSTR)screen in your call to WriteConsoleOutputCharacter is an indication something isn't right.
In this case, screen is a char but you want it to be wchar_t instead. You're already using wstring for tetromine, and L prefixed character strings. You just need to ensure the rest of the code is also using wide characters.

Scaling png font down

Is there a way to scale down with highest quality a font which is png image in opengl at startup? I tried gluScaleImage but there are many artefacts. Is there anything that uses lanczos or something like that? I don't want to write a shader or anything that does the scaling runtime.
This is based on an algorithm, I copied decades ago from the German c't Magazin, and still use it from time to time for similar issues like described by OP.
bool scaleDown(
const Image &imgSrc,
Image &imgDst,
int w, int h,
int align)
{
const int wSrc = imgSrc.w(), hSrc = imgSrc.h();
assert(w > 0 && w <= wSrc && h > 0 && h <= hSrc);
// compute scaling factors
const double sx = (double)wSrc / (double)w;
const double sy = (double)hSrc / (double)h;
const double sxy = sx * sy;
// prepare destination image
imgDst.resize(w, h, (w * 3 + align - 1) / align * align);
// cache some data
const uint8 *const dataSrc = imgSrc.data();
const int bPRSrc = imgSrc.bPR();
// perform scaling
for (int y = 0; y < h; ++y) {
const double yStart = sy * y;
const double yEnd = std::min(sy * (y + 1), (double)hSrc);
const int yStartInt = (int)yStart;
const int yEndInt = (int)yEnd - (yEndInt == yEnd);
const double tFrm = 1 + yStartInt - yStart, bFrm = yEnd - yEndInt;
for (int x = 0; x < w; ++x) {
const double xStart = sx * x;
const double xEnd = std::min(sx * (x + 1), (double)wSrc);
const int xStartInt = (int)xStart;
const int xEndInt = (int)xEnd - (xEndInt == xEnd);
double lFrm = 1 + xStartInt - xStart, rFrm = xEnd - xEndInt;
double pixel[3] = { 0.0, 0.0, 0.0 }; // values of target pixel
for (int i = yStartInt; i <= yEndInt; ++i) {
int jData = i * bPRSrc + xStartInt * 3;
for (int j = xStartInt; j <= xEndInt; ++j) {
double pixelAdd[3];
for (int k = 0; k < 3; ++k) {
pixelAdd[k] = (double)dataSrc[jData++] / sxy;
}
if (j == xStartInt) {
for (int k = 0; k < 3; ++k) pixelAdd[k] *= lFrm;
} else if (j == xEndInt) {
for (int k = 0; k < 3; ++k) pixelAdd[k] *= rFrm;
}
if (i == yStartInt) {
for (int k = 0; k < 3; ++k) pixelAdd[k] *= tFrm;
} else if (i == yEndInt) {
for (int k = 0; k < 3; ++k) pixelAdd[k] *= bFrm;
}
for (int k = 0; k < 3; ++k) pixel[k] += pixelAdd[k];
}
}
imgDst.setPixel(x, y,
(uint8)pixel[0], (uint8)pixel[1], (uint8)pixel[2]);
}
}
// done
return true;
}
If I got it right, this implements a bilinear interpolation.
I don't dare to call it a Minimal Complete Verifiable Example although this is what I intended to do.
The complete sample application:
A simplified class Image
image.h:
#ifndef IMAGE_H
#define IMAGE_H
#include <vector>
// convenience type for bytes
typedef unsigned char uint8;
// image helper class
class Image {
private: // variables:
int _w, _h; // image size
size_t _bPR; // bytes per row
std::vector<uint8> _data; // image data
public: // methods:
// constructor.
Image(): _w(0), _h(0), _bPR(0) { }
// destructor.
~Image() = default;
// copy constructor.
Image(const Image&) = delete; // = default; would work as well.
// copy assignment.
Image& operator=(const Image&) = delete; // = default; would work as well.
// returns width of image.
int w() const { return _w; }
// returns height of image.
int h() const { return _h; }
// returns bytes per row.
size_t bPR() const { return _bPR; }
// returns pointer to image data.
const uint8* data(
int y = 0) // row number
const {
return &_data[y * _bPR];
}
// returns data size (in bytes).
size_t size() const { return _data.size(); }
// clears image.
void clear();
// resizes image.
uint8* resize( // returns allocated buffer
int w, // image width
int h, // image height
int bPR); // bytes per row
// returns pixel.
int getPixel(
int x, // column
int y) // row
const;
// sets pixel.
void setPixel(
int x, // column
int y, // row
uint8 r, uint8 g, uint8 b);
// sets pixel.
void setPixel(
int x, // column
int y, // row
int value) // RGB value
{
setPixel(x, y, value & 0xff, value >> 8 & 0xff, value >> 16 & 0xff);
}
};
// helper functions:
inline uint8 getR(int value) { return value & 0xff; }
inline uint8 getG(int value) { return value >> 8 & 0xff; }
inline uint8 getB(int value) { return value >> 16 & 0xff; }
#endif // IMAGE_H
image.cc:
#include <cassert>
#include "image.h"
// clears image.
void Image::clear()
{
_data.clear(); _w = _h = _bPR = 0;
}
// allocates image data.
uint8* Image::resize( // returns allocated buffer
int w, // image width
int h, // image height
int bPR) // bits per row
{
assert(w >= 0 && 3 * w <= bPR);
assert(h >= 0);
_w = w; _h = h; _bPR = bPR;
const size_t size = h * bPR;
_data.resize(size);
return _data.data();
}
// returns pixel.
int Image::getPixel(
int x, // column
int y) // row
const {
assert(x >= 0 && x < _w);
assert(y >= 0 && y < _h);
const size_t offs = y * _bPR + 3 * x;
return _data[offs + 0]
| _data[offs + 1] << 8
| _data[offs + 2] << 16;
}
// sets pixel.
void Image::setPixel(
int x, // column
int y, // row
uint8 r, uint8 g, uint8 b) // R, G, B values
{
assert(x >= 0 && x < _w);
assert(y >= 0 && y < _h);
const size_t offs = y * _bPR + 3 * x;
_data[offs + 0] = r;
_data[offs + 1] = g;
_data[offs + 2] = b;
}
Image Scaling
imageScale.h:
#ifndef IMAGE_SCALE_H
#define IMAGE_SCALE_H
#include "image.h"
/* scales an image to a certain width and height.
*
* Note:
* imgSrc and imgDst may not be identical.
*/
bool scaleTo( // returns true if successful
const Image &imgSrc, // source image
Image &imgDst, // destination image
int w, int h, // destination width and height
int align = 4); // row alignment
/* scales an image about a certain horizontal/vertical scaling factor.
*
* Note:
* imgSrc and imgDst may not be identical.
*/
inline bool scaleXY( // returns true if successful
const Image &imgSrc, // source image
Image &imgDst, // destination image
double sX, // horizontal scaling factor (must be > 0 but not too large)
double sY, // vertical scaling factor (must be > 0 but not too large)
int align = 4) // row alignment
{
return sX > 0.0 && sY > 0.0
? scaleTo(imgSrc, imgDst,
(int)(sX * imgSrc.w()), (int)(sY * imgSrc.h()), align)
: false;
}
/* scales an image about a certain scaling factor.
*
* Note:
* imgSrc and imgDst may not be identical.
*/
inline bool scale( // returns true if successful
const Image &imgSrc, // source image
Image &imgDst, // destination image
double s, // scaling factor (must be > 0 but not too large)
int align = 4) // row alignment
{
return scaleXY(imgSrc, imgDst, s, s, align);
}
#endif // IMAGE_SCALE_H
imageScale.cc:
#include <cassert>
#include <algorithm>
#include "imageScale.h"
namespace {
template <typename VALUE>
VALUE clip(VALUE value, VALUE min, VALUE max)
{
return value < min ? min : value > max ? max : value;
}
bool scaleDown(
const Image &imgSrc,
Image &imgDst,
int w, int h,
int align)
{
const int wSrc = imgSrc.w(), hSrc = imgSrc.h();
assert(w > 0 && w <= wSrc && h > 0 && h <= hSrc);
// compute scaling factors
const double sx = (double)wSrc / (double)w;
const double sy = (double)hSrc / (double)h;
const double sxy = sx * sy;
// prepare destination image
imgDst.resize(w, h, (w * 3 + align - 1) / align * align);
// cache some data
const uint8 *const dataSrc = imgSrc.data();
const int bPRSrc = imgSrc.bPR();
// perform scaling
for (int y = 0; y < h; ++y) {
const double yStart = sy * y;
const double yEnd = std::min(sy * (y + 1), (double)hSrc);
const int yStartInt = (int)yStart;
const int yEndInt = (int)yEnd - (yEndInt == yEnd);
const double tFrm = 1 + yStartInt - yStart, bFrm = yEnd - yEndInt;
for (int x = 0; x < w; ++x) {
const double xStart = sx * x;
const double xEnd = std::min(sx * (x + 1), (double)wSrc);
const int xStartInt = (int)xStart;
const int xEndInt = (int)xEnd - (xEndInt == xEnd);
double lFrm = 1 + xStartInt - xStart, rFrm = xEnd - xEndInt;
double pixel[3] = { 0.0, 0.0, 0.0 }; // values of target pixel
for (int i = yStartInt; i <= yEndInt; ++i) {
int jData = i * bPRSrc + xStartInt * 3;
for (int j = xStartInt; j <= xEndInt; ++j) {
double pixelAdd[3];
for (int k = 0; k < 3; ++k) {
pixelAdd[k] = (double)dataSrc[jData++] / sxy;
}
if (j == xStartInt) {
for (int k = 0; k < 3; ++k) pixelAdd[k] *= lFrm;
} else if (j == xEndInt) {
for (int k = 0; k < 3; ++k) pixelAdd[k] *= rFrm;
}
if (i == yStartInt) {
for (int k = 0; k < 3; ++k) pixelAdd[k] *= tFrm;
} else if (i == yEndInt) {
for (int k = 0; k < 3; ++k) pixelAdd[k] *= bFrm;
}
for (int k = 0; k < 3; ++k) pixel[k] += pixelAdd[k];
}
}
imgDst.setPixel(x, y,
(uint8)pixel[0], (uint8)pixel[1], (uint8)pixel[2]);
}
}
// done
return true;
}
bool scaleUp(
const Image &imgSrc,
Image &imgDst,
int w, int h,
int align)
{
const int wSrc = imgSrc.w(), hSrc = imgSrc.h();
assert(w && w >= wSrc && h && h >= hSrc);
// compute scaling factors
const double sx = (double)wSrc / (double)w;
const double sy = (double)hSrc / (double)h;
// prepare destination image
imgDst.resize(w, h, (w * 3 + align - 1) / align * align);
// cache some data
const uint8 *const dataSrc = imgSrc.data();
const int bPRSrc = imgSrc.bPR();
// perform scaling
for (int y = 0; y < h; ++y) {
const double yStart = sy * y;
const double yEnd = std::min(sy * (y + 1), (double)hSrc - 1);
const int yStartInt = (int)yStart;
const int yEndInt = (int)yEnd;
if (yStartInt < yEndInt) {
const double bFract = clip((double)((yEnd - yEndInt) / sy), 0.0, 1.0);
const double tFract = 1.0 - bFract;
for (int x = 0; x < w; ++x) {
const double xStart = sx * x;
const double xEnd = std::min(sx * (x + 1), (double)wSrc - 1);
const int xStartInt = (int)xStart, xEndInt = (int)xEnd;
double pixel[4];
if (xStartInt < xEndInt) {
const double rFract
= clip((double)((xEnd - xEndInt) / sx), 0.0, 1.0);
const double lFract = 1.0 - rFract;
int jData = yStartInt * bPRSrc + xStartInt * 3;
for (int k = 0; k < 3; ++k) {
pixel[k] = tFract * lFract * dataSrc[jData++];
}
for (int k = 0; k < 3; ++k) {
pixel[k] += tFract * rFract * dataSrc[jData++];
}
jData = yEndInt * bPRSrc + xStartInt * 3;
for (int k = 0; k < 3; ++k) {
pixel[k] += bFract * lFract *dataSrc[jData++];
}
for (int k = 0; k < 3; ++k) {
pixel[k] += bFract * rFract *dataSrc[jData++];
}
} else {
int jData = yStartInt * bPRSrc + xStartInt * 3;
for (int k = 0; k < 3; ++k) {
pixel[k] = tFract * dataSrc[jData++];
}
jData = yEndInt * bPRSrc + xStartInt * 3;
for (int k = 0; k < 3; ++k) {
pixel[k] += bFract * dataSrc[jData++];
}
}
imgDst.setPixel(x, y,
(uint8)pixel[0], (uint8)pixel[1], (uint8)pixel[2]);
}
} else {
for (int x = 0; x < w; ++x) {
const double xStart = sx * x;
const double xEnd = std::min(sx * (x + 1), (double)wSrc - 1);
const int xStartInt = (int)xStart, xEndInt = (int)xEnd;
double pixel[3];
if (xStartInt < xEndInt) {
const double rFract
= clip((double)((xEnd - xEndInt) / sx), 0.0, 1.0);
const double lFract = 1.0 - rFract;
int jData = yStartInt * bPRSrc + xStartInt * 3;
for (int k = 0; k < 3; ++k) {
pixel[k] = lFract * dataSrc[jData++];
}
for (int k = 0; k < 3; ++k) {
pixel[k] += rFract * dataSrc[jData++];
}
} else {
int jData = yStartInt * bPRSrc + xStartInt * 3;
for (int k = 0; k < 3; ++k) pixel[k] = dataSrc[jData++];
}
imgDst.setPixel(x, y,
(uint8)pixel[0], (uint8)pixel[1], (uint8)pixel[2]);
}
}
}
// done
return true;
}
} // namespace
bool scaleTo(const Image &imgSrc, Image &imgDst, int w, int h, int align)
{
Image imgTmp;
return w <= 0 || h <= 0 ? false
: w >= imgSrc.w() && h >= imgSrc.h()
? scaleUp(imgSrc, imgDst, w, h, align)
: w <= imgSrc.w() && h <= imgSrc.h()
? scaleDown(imgSrc, imgDst, w, h, align)
: w >= imgSrc.w()
? scaleUp(imgSrc, imgTmp, w, imgSrc.h(), 1)
&& scaleDown(imgTmp, imgDst, w, h, align)
: scaleDown(imgSrc, imgTmp, w, imgSrc.h(), 1)
&& scaleUp(imgTmp, imgDst, w, h, align);
}
PPM file IO
imagePPM.h:
#ifndef IMAGE_PPM_H
#define IMAGE_PPM_H
#include <iostream>
#include "image.h"
// reads a binary PPM file.
bool readPPM( // returns true if successful
std::istream &in, // input stream (must be opened with std::ios::binary)
Image &img, // image to read into
int align = 4); // row alignment
// writes binary PPM file.
bool writePPM( // returns true if successful
std::ostream &out, // output stream (must be opened with std::ios::binary)
const Image &img); // image to write from
#endif // IMAGE_PPM_H
imagePPM.cc:
#include <sstream>
#include <string>
#include "imagePPM.h"
// reads a binary PPM file.
bool readPPM( // returns true if successful
std::istream &in, // input stream (must be opened with std::ios::binary)
Image &img, // image to read into
int align) // row alignment
{
// parse header
std::string buffer;
if (!getline(in, buffer)) return false;
if (buffer != "P6") {
std::cerr << "Wrong header! 'P6' expected.\n";
return false;
}
int w = 0, h = 0, t = 0;
for (int i = 0; i < 3;) {
if (!getline(in, buffer)) return false;
if (buffer.empty()) continue; // skip empty lines
if (buffer[0] == '#') continue; // skip comments
std::istringstream str(buffer);
switch (i) {
case 0:
if (!(str >> w)) continue;
++i;
case 1:
if (!(str >> h)) continue;
++i;
case 2:
if (!(str >> t)) continue;
++i;
}
}
if (t != 255) {
std::cerr << "Unsupported format! t = 255 expected.\n";
return false;
}
// allocate image buffer
uint8 *data = img.resize(w, h, (w * 3 + align - 1) / align * align);
// read data
for (int i = 0; i < h; ++i) {
if (!in.read((char*)data, 3 * img.w())) return false;
data += img.bPR();
}
// done
return true;
}
// writes binary PPM file.
bool writePPM( // returns true if successful
std::ostream &out, // output stream (must be opened with std::ios::binary)
const Image &img) // image to write from
{
// write header
if (!(out << "P6\n" << img.w() << ' ' << img.h() << " 255\n")) return false;
// write image data
for (size_t y = 0; y < img.h(); ++y) {
const uint8 *const data = img.data(y);
if (!out.write((const char*)data, 3 * img.w())) return false;
}
// done
return true;
}
The main application
scaleRGBImg.cc:
#include <iostream>
#include <fstream>
#include <string>
#include "image.h"
#include "imagePPM.h"
#include "imageScale.h"
int main(int argc, char **argv)
{
// read command line arguments
if (argc <= 3) {
std::cerr << "Missing arguments!\n";
std::cout
<< "Usage:\n"
<< " scaleRGBImg IN_FILE SCALE OUT_FILE\n";
return 1;
}
const std::string inFile = argv[1];
char *end;
const double s = std::strtod(argv[2], &end);
if (end == argv[2] || *end != '\0') {
std::cerr << "Invalid scale factor '" << argv[2] << "'!\n";
return 1;
}
if (s <= 0.0) {
std::cerr << "Invalid scale factor " << s << "!\n";
return 1;
}
const std::string outFile = argv[3];
// read image
Image imgSrc;
{ std::ifstream fIn(inFile.c_str(), std::ios::binary);
if (!readPPM(fIn, imgSrc)) {
std::cerr << "Reading '" << inFile << "' failed!\n";
return 1;
}
}
// scale image
Image imgDst;
if (!scale(imgSrc, imgDst, s)) {
std::cerr << "Scaling failed!\n";
return 1;
}
// write image
{ std::ofstream fOut(outFile.c_str(), std::ios::binary);
if (!writePPM(fOut, imgDst) || (fOut.close(), !fOut.good())) {
std::cerr << "Writing '" << outFile << "' failed!\n";
return 1;
}
}
// done
return 0;
}
Test
Compiled in cygwin64:
$ g++ -std=c++11 -o scaleRGBImg scaleRGBImg.cc image.cc imagePPM.cc imageScale.cc
$
A sample image test.ppm for a test – converted to PPM in GIMP:
Test with the sample image:
$ for I in 0.8 0.6 0.4 0.2 ; do echo ./scaleRGBImg test.ppm $I test.$I.ppm ; done
./scaleRGBImg test.ppm 0.8 test.0.8.ppm
./scaleRGBImg test.ppm 0.6 test.0.6.ppm
./scaleRGBImg test.ppm 0.4 test.0.4.ppm
./scaleRGBImg test.ppm 0.2 test.0.2.ppm
$ for I in 0.8 0.6 0.4 0.2 ; do ./scaleRGBImg test.ppm $I test.$I.ppm ; done
$
This is what came out:
test.0.8.ppm:
test.0.6.ppm:
test.0.4.ppm:
test.0.2.ppm:

Memory leak while using SDL2 Texture

I am in the progress of making a game which uses SDL_TTF and SDL_Image. I have one function called browseinventory which allows you to check out the stats of an item once you hover over it. That's where the memory leak occurs. Baically once you've hovered over an item slot the program check if there's anything in said slot and if there is, Text class objects are set with the item's parameters and then rendered.
I am pretty sure that the fault lies within the Text class, as memory usage rapidly increases once I've hovered over an item.
Text class:
class Text
{
public:
Text() {w = 0; h = 0; saying = ""; Textthing = NULL;}
~Text(){destroy();}
void destroy(){SDL_DestroyTexture(Textthing); Textthing = 0; saying = "", w = 0, h = 0;}
void render(int, int, int, SDL_Renderer*);
void settext(string, SDL_Color);
void rendertest(int, int, SDL_Renderer*);
int rows;
private:
string saying;
SDL_Texture *Textthing;
int w, h;
unsigned int flag1 = 0, flag2, loops = 0;
string saying1;
unsigned int counter;
bool spaceflag = 0;
};
render():
void Text::render(int x, int y, int maxchars = 100, SDL_Renderer *Temp = Saviour)
{
rows = 0;
flag1 = 0, flag2 = maxchars, loops = 0;
int increment = maxchars;
if (resolution == "800x600")
{
flag2 = maxchars*0.8;
increment = maxchars*0.8;
}
spaceflag = 0;
do
{
spaceflag = 0;
for (counter = flag1; counter < flag2 && counter < saying.length(); counter++)
{
if (counter > flag2-10 && saying[counter] == ' ')
{
spaceflag = 1;
break;
}
saying1 += saying[counter];
}
asdfgfa1.settext(saying1);
asdfgfa1.rendertest(x, y + loops*(SCREEN_HEIGHT/19), Temp);
saying1 = "";
loops++;
rows++;
if (flag2 > saying.length())
break;
if (spaceflag == 0)
{
flag1 = flag2;
flag2 += increment;
}
else
{
flag1 = counter;
flag2 = counter + increment;
}
}while (1);
asdfgfa1.destroy();
SDL_DestroyTexture(Textthing);
Textthing = 0;
}
setText():
void Text::settext(string stuff, SDL_Color Colour = {255, 255, 255})
{
saying = stuff;
SDL_Surface *Surf = TTF_RenderText_Solid(Arial, stuff.c_str(), Colour);
w = Surf->w;
h = Surf->h;
Textthing = SDL_CreateTextureFromSurface(Saviour, Surf);
SDL_FreeSurface(Surf);
Surf = 0;
}