I´m working on a small Microsoft paint-like program to learng VGA 256 color programming on C.
I have been able to plot a pixel when the user clicks on the screen and keep ploting the pixels while the mouse button is pressed. However if I move the mouse fast across the screen, I don´t get a continous line. Instead I get this result
How can I make the line be continous even when there are fast mouse movements?
Heres the code I have until now:
/**************************************************************************
* paint_screen *
* show main screen paint *
**************************************************************************/
void paint_screen(BITMAP *fondo){
int mantenido;
BITMAP barra,barra_color,normal_ptr_image;
int anterior_presionado;
word last_time;
word redraw,press,release;
sword dx,dy=0;
MOUSEBITMAP *mouse_new=NULL;
int i,done = 0;
accion =1;
/*Pintando fondo blanco*/
clear_screen();
/*Pintando barra de herramientas*/
load_bmp("normal.bmp",&normal_ptr_image);
load_bmp("mainbar.bmp",&barra);
load_bmp("colores.bmp",&barra_color);
set_pallete(fondo->pallete);
draw_bitmap(&barra,0,0);
draw_bitmap(&barra_color,0,180);
load_mouse(&mouse_g);
show_mouse(&mouse_g);
wait(50);
while(!done){
do { // check mouse status
anterior_presionado = press;
get_mouse_motion(&dx,&dy);
press = get_mouse_press(LEFT_BUTTON);
release = get_mouse_release(LEFT_BUTTON);
//Si el estado estaba presionado y no se ha soltado.. el boton esta mantenido
if(anterior_presionado==1 &&release==0){
mantenido =1;
}
} while (dx==0 && dy==0 && press==0 && release==0&&*my_clock==last_time);
if (release){
mouse_g.button1=0;
mantenido=0;
boton_soltado();
}
if (press){
mouse_g.button1=1;
boton_presionado();
}
//El boton se mantiene presionado
else if(mantenido){
boton_mantenido();
}
else{
release=1;
}
if (dx || dy) // calculate movement
{
new_x1 = mouse_g.x+dx;
new_y1 = mouse_g.y+dy; //Actualizamos posicion mouse
if (new_x1<0) new_x1=0;
if (new_y1<0) new_y1=0;
if (new_x1>319) new_x1=319;
if (new_y1>199) new_y1=199;
redraw=1;
}
if(redraw){
wait_for_retrace();
hide_mouse(&mouse_g);
if (mouse_new!=NULL) mouse_g.bmp=mouse_new;
mouse_g.x = new_x1;
mouse_g.y=new_y1;
show_mouse(&mouse_g);
redraw=0;
mouse_new=NULL;
}
if(new_x1>=287 && new_x1 <320
&& new_y1>=180 && new_y1 < 200 &&press){
set_mode(TEXT_MODE);
printf("Adios!!");
wait(25);
done=0;
return;
}
}
}
void realizar_accion(){
/*Caso1: Pintar pixel simple (lapiz)*/
if(accion==1){
plot_pixel(mouse_g.x,mouse_g.y,2);
plot_pixel(mouse_g.x-1,mouse_g.y,2);
plot_pixel(mouse_g.x,mouse_g.y-1,2);
plot_pixel(mouse_g.x-1,mouse_g.y-1,2);
}
}
void realizar_accion_mantenido(){
if(accion==1){
plot_pixel(mouse_g.x,mouse_g.y,2);
plot_pixel(mouse_g.x-1,mouse_g.y,2);
plot_pixel(mouse_g.x,mouse_g.y-1,2);
plot_pixel(mouse_g.x-1,mouse_g.y-1,2);
}
}
int sobre_barra(){
if(new_x1>0 && new_x1<33 &&new_y1>0 &&new_y1<181){
return 1;
}
else{
return -1;
}
}
void boton_mantenido(){
/*Verificar que este dento del buffer de dibujo....*/
if(sobre_barra()!=1){
realizar_accion_mantenido();
}
}
void boton_presionado(){
if(sobre_barra()==1){
cambiar_herramienta();
}
else{
realizar_accion();
}
}
Related
I have an issue with my code. I don't manage to change the opacity of my RenderDrawColor.
Indeed, I know that SetRenderDrawColor is defined by (renderer, R, G, B, a --> which represents the opacity value). Nevertheless, I tried to change a value but my color doesn't change and I have my rectangle fully fill again.
Here a photo of what I have with my code :
Screen that I have with my code
Here is my code, that I execute with a main.c script :
void display_end_menu(SDL_Renderer *renderer) {
if (SDL_SetRenderDrawColor(renderer, 0, 255, 0, 30) != 0) {
return_error("Impossible de modifier la couleur du render");
SDL_Quit();
}
SDL_Rect shadow_screen;
shadow_screen.w = 1280;
shadow_screen.h = 720;
shadow_screen.x = (SCREEN_WIDTH - shadow_screen.w)/2;
shadow_screen.y = (SCREEN_HEIGHT - shadow_screen.h)/2;
if (SDL_RenderFillRect(renderer, &shadow_screen) != 0) {
return_error("Impossible de dessiner le rectangle dans le render");
SDL_Quit();
}
if (SDL_SetRenderDrawColor(renderer, 255, 255, 255, 30) != 0) {
return_error("Impossible de modifier la couleur du render");
SDL_Quit();
}
SDL_Rect quit_button;
quit_button.w = 200;
quit_button.h = 50;
quit_button.x = (SCREEN_WIDTH - quit_button.w)/2;
quit_button.y = (SCREEN_HEIGHT - quit_button.h)/2;
if (SDL_RenderFillRect(renderer, &quit_button) != 0) {
return_error("Impossible de dessiner le rectangle dans le render");
SDL_Quit();
}
}
I tried several numbers for alpha such as 0, 30 and so on, but it's impossible to edit the opacity of the rectangle.
I'm writing a EA for strategy tester purpose only, to evaluate portfolio. So I have hundreads/thousands of trades in an array, with open price and open time, and every 1 minute bar I check in a for loop if there's any trade to open in that minute. And it's taking forever.
How can I check (in a faster way) if in an array there's a open-time that coincides with current time?
Thanks!
if(NewBar)
{
CopyRates(_Symbol,PERIOD_M1,0,5,candle);
sizeAr=ArraySize(ar);
arColumns=ArrayRange(ar,1);
datetime candleNowTime = candle[0].time;
datetime nextCandleTime = candle[0].time+60;
for(int i=0;i<sizeAr/arColumns;i++)
{
if(ar[i][openTime]>candleNowTime && ar[i][openTime]<nextCandleTime)
{
//code to open trades
}
}
}
And the complete code is here:
//+------------------------------------------------------------------+
//| HedgeExperienceV001.mq5 |
//| Carlos Duna |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Carlos Duna"
#property link "https://www.mql5.com"
#property version "1.00"
#property tester_file "sinais.csv"
#include <Trade\Trade.mqh>
CTrade trade;
#include <Trade\SymbolInfo.mqh>
CSymbolInfo mysymbol;
#define columns 19
input double initialVolume = 0.01; // Volume inicial
input double slFixo = 0; // SL fixo (pips)(zero=SL do sinal)
input double tpFixo = 0; // TP fixo (pips)(zero=TP do sinal)
input ulong maxSlippage = 0; // Max Deviation/Slippage(0-não usa)
input double maxPricesVariation =10;// Max % variação Bid x TP x SL x OP
MqlRates candle[];
MqlDateTime TimeStruct;
MqlDateTime dealDay;
datetime dealDayStruct;
datetime now;
int secAnterior;
int previousDay;
bool NewBar;
datetime hj;
string orderComment;
bool orderOkToOpen;
datetime inicioHedge=0;
double profitPerMagic[][2];
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
struct SLine
{
string field[];
};
SLine lines[];
string ar[][columns];
int sizeLine;
int sizeAr;
int arColumns;
double stopLossDelta;
double takeProfitDelta;
/*
lines[i].field[j]
** i= numero de cada trade, iniciando no zero (não há títulos de colunas), indo dinamicamente até a ultima linha
** j= valores dos campos
0 - tCanal
1 - str(msgId)
2 - dataHora HoraEntrada
3 - str(opType) CompraOuVenda
4 - ativo.upper()
5 - str(openPrice)
6 - str(stopLoss)
7 - str(takeProfit1)
8 - str(takeProfit2)
9 - str(takeProfit3)
10 - str(takeProfit4)
11 - str(takeProfit5)
12 - 'false' posição já foi aberta? true/false
13 - 'false' posição já foi fechada? true/false
14 - HalfCloseTime
15 - ManualCloseTime
16 - SLModify_Time
17 - SLModify_Price])
18 - magicCanal
*/
int xCanal = 0; // tCanal
int xOpCod = 1; // str(msgId)
int xDtEnt = 2; // dataHora HoraEntrada
int xBuySell=3; // str(opType) CompraOuVenda
int xAtv= 4; // ativo.upper()
int xOP = 5; // str(openPrice)
int xSL=6; // str(stopLoss)
int xTP1 = 7; // str(takeProfit1)
int xTP2 = 8; // str(takeProfit2)
int xTP3 = 9; // str(takeProfit3)
int xTP4 = 10; // str(takeProfit4)
int xTP5 = 11; // str(takeProfit5)
int xOpened = 12; // posição já foi aberta? true/false
int xClosed = 13; // posição já foi fechada? true/false
int xHalfC=14; // HalfCloseTime
int xManualC = 15; // ManualCloseTime
int xSLMTime = 16; // SLModify_Time
int xSLMPrice= 17; // SLModify_Price
int xMagic=18; // magicCanal
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
ArraySetAsSeries(candle,true);
if(!ReadFileToArrayCSV("sinais.csv",lines))
{
Alert("Error, see the \"Experts\" tab for details");
return(INIT_FAILED);
}
sizeLine=ArraySize(lines);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
ArrayFree(lines);
ArrayFree(ar);
double a = ProfitClosedPosition();
Print(a);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
now=TimeCurrent();
TimeToStruct(TimeCurrent(),TimeStruct);
if(previousDay!=TimeStruct.day_of_year) //Runs once a day
{
previousDay=TimeStruct.day_of_year;
// recria diariamente o array auxiliar ar
ArrayResize(ar,sizeLine);
for(int i=0;i<sizeLine;i++)
{
for(int j=0;j<columns;j++)
{
ar[i][j]=lines[i].field[j];
}
}
// após array ar recriado, elimina-se o que não for ser usado no dia
for(int i=sizeLine-1; i>=0; i--)
{
TimeToStruct((datetime)lines[i].field[xDtEnt],dealDay);
// if temporario; o deal close não será por data, e sim pelo fechamento do trade, a ser sinalizado no futuro
if(dealDay.day_of_year+2<TimeStruct.day_of_year && dealDay.year==TimeStruct.year)
{
ArrayRemove(ar,i,1);
}
// remove entradas cujas datas de entrada sejam superiores ao dia de hoje ou que possuam flag 'closed'
if((dealDay.day_of_year>TimeStruct.day_of_year && dealDay.year<=TimeStruct.year) || (lines[i].field[xClosed]==true))
{
ArrayRemove(ar,i,1);
}
}
}
NewBar=isNewBar();
if(NewBar)
{
CopyRates(_Symbol,PERIOD_M1,0,5,candle);
sizeAr=ArraySize(ar);
arColumns=ArrayRange(ar,1);
datetime candleNowTime = candle[0].time;
datetime nextCandleTime = candle[0].time+60;
for(int i=0;i<sizeAr/arColumns;i++)
{
if(ar[i][xDtEnt]>candleNowTime && ar[i][xDtEnt]<nextCandleTime)
{
fAbrirOp(i);
Print(ar[i][xCanal]," / ",ar[i][xOP]," / ",ar[i][xSL]," / ",ar[i][xTP1]);
}
}
}
}
//+------------------------------------------------------------------+
//| Função que transforma arquivo CSV em array |
//+------------------------------------------------------------------+
bool ReadFileToArrayCSV(string FileName,SLine &Lines[])
{
ResetLastError();
int h=FileOpen(FileName,FILE_READ|FILE_ANSI|FILE_CSV|FILE_COMMON,";");
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(h==INVALID_HANDLE)
{
int ErrNum=GetLastError();
printf("Error opening file %s # %i",FileName,ErrNum);
return(false);
}
int lcnt=0; // variable for calculating lines
int fcnt=0; // variable for calculating line fields
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
while(!FileIsEnding(h))
{
string str=FileReadString(h);
// new line (new element of the structure array)
if(lcnt>=ArraySize(Lines))
{ // structure array completely filled
ArrayResize(Lines,ArraySize(Lines)+1024); // increase the array size by 1024 elements
}
ArrayResize(Lines[lcnt].field,64);// change the array size in the structure
Lines[lcnt].field[0]=str; // assign the first field value
// start reading other fields in the line
fcnt=1; // till one element in the line array is occupied
while(!FileIsLineEnding(h))
{ // read the rest of fields in the line
str=FileReadString(h);
if(fcnt>=ArraySize(Lines[lcnt].field))
{ // field array is completely filled
ArrayResize(Lines[lcnt].field,ArraySize(Lines[lcnt].field)+64); // increase the array size by 64 elements
}
Lines[lcnt].field[fcnt]=str; // assign the value of the next field
fcnt++; // increase the line counter
}
ArrayResize(Lines[lcnt].field,fcnt); // change the size of the field array according to the actual number of fields
lcnt++; // increase the line counter
}
ArrayResize(Lines,lcnt); // change the array of structures (lines) according to the actual number of lines
FileClose(h);
return(true);
}
//+------------------------------------------------------------------+
//| Função checar nova barra |
//+------------------------------------------------------------------+
bool isNewBar(void)
{
//--- memorize the time of opening of the last bar in the static variable
static datetime last_time=0;
//--- current time
datetime lastbar_time=(datetime)SeriesInfoInteger(Symbol(),PERIOD_M1,SERIES_LASTBAR_DATE);
//--- if it is the first call of the function
if(last_time==0)
{
//--- set the time and exit
last_time=lastbar_time;
return(false);
}
//--- if the time differs
if(last_time!=lastbar_time)
{
//--- memorize the time and return true
last_time=lastbar_time;
return(true);
}
//--- if we passed to this line, then the bar is not new; return false
return(false);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| entrada em operação |
//+------------------------------------------------------------------+
void fAbrirOp(int i)
{
if(inicioHedge==0)inicioHedge=datetime(ar[i][xDtEnt]);
double _TP;
double _SL;
orderOkToOpen=true;
Print("iniciando ativo: ",ar[i][xAtv]);
if(!mysymbol.Name(ar[i][xAtv]))
{
Print("Erro ao selecionar ativo ",ar[i][xAtv],"; operação não será aberta.");
orderOkToOpen=false;
}
mysymbol.RefreshRates();
double spread=mysymbol.Spread();
double bid = mysymbol.Bid();
double ask = mysymbol.Ask();
double maxPrice = ask * (100 + maxPricesVariation)/100;
double minPrice = bid * (100 - maxPricesVariation)/100;
//--- tuning for 3 or 5 digits
int digits_adjust=1;
if(mysymbol.Digits()==3 || mysymbol.Digits()==5)
digits_adjust=10;
stopLossDelta = slFixo*digits_adjust;
takeProfitDelta = tpFixo*digits_adjust;
if(maxSlippage!=0) trade.SetDeviationInPoints(maxSlippage);
if(double(ar[i][xOP])<minPrice || double(ar[i][xOP])>maxPrice || double(ar[i][xSL])<minPrice || double(ar[i][xSL])>maxPrice || double(ar[i][xTP1])<minPrice || double(ar[i][xTP1])>maxPrice)
{
Print("Erro nos níveis de preço do ativo ",ar[i][xAtv],". Bid = ",bid," / Open Price: ",ar[i][xOP]," / SL: ",ar[i][xSL]," / TP: ",ar[i][xTP1]," operação não será aberta.");
orderOkToOpen=false;
}
if(orderOkToOpen)
{
trade.SetExpertMagicNumber(ulong(ar[i][xMagic]));
if(ar[i][xBuySell]=="buy")
{
_TP = tpFixo == 0 ? double(ar[i][xTP1]) : double(ar[i][xOP]) + takeProfitDelta;
_SL = slFixo == 0 ? double(ar[i][xSL]) : double(ar[i][xOP]) - stopLossDelta;
if(trade.Buy(initialVolume,ar[i][xAtv],double(ar[i][xOP]),_SL,_TP,ar[i][xCanal]))
{
ar[i][xOpened]=true;
Print("Ordem colocada, ticket: ",trade.ResultDeal());
Print("preço: ",trade.ResultPrice()," , era pra ter sido por ",ar[i][xOP]);
trade.PrintResult();
}
else
{
Print(trade.ResultRetcodeDescription());
trade.PrintRequest();
}
}
else if(ar[i][xBuySell]=="sell")
{
_TP = tpFixo == 0 ? double(ar[i][xTP1]) : double(ar[i][xOP]) - takeProfitDelta;
_SL = slFixo == 0 ? double(ar[i][xSL]) : double(ar[i][xOP]) + stopLossDelta;
if(trade.Sell(initialVolume,ar[i][xAtv],double(ar[i][xOP]),_SL,_TP,ar[i][xCanal]))
{
ar[i][xOpened]=true;
Print("Ordem colocada, ticket: ",trade.ResultDeal());
Print("preço: ",trade.ResultPrice()," , era pra ter sido por ",ar[i][xOP]);
trade.PrintResult();
}
else
{
Print(trade.ResultRetcodeDescription());
trade.PrintRequest();
}
}
}
}
//+------------------------------------------------------------------+
//| Lucro acumulado do dia |
//+------------------------------------------------------------------+
double ProfitClosedPosition()
{
int lSize;
bool magicFound;
double profit=0;
int counter=1;
HistorySelect(inicioHedge,TimeCurrent());
int deals=HistoryDealsTotal();
int colunas = ArrayRange(profitPerMagic,1);
//---
for(int i=0;i<deals;i++)
{
ulong deal_ticket=HistoryDealGetTicket(i);
string symbol= HistoryDealGetString(deal_ticket,DEAL_SYMBOL);
double _p_profit=HistoryDealGetDouble(deal_ticket,DEAL_PROFIT);
int dealType = (int)HistoryDealGetInteger(deal_ticket,DEAL_TYPE);
int dealMagic = (int)HistoryDealGetInteger(deal_ticket,DEAL_MAGIC);
string dealComment =HistoryDealGetString(deal_ticket,DEAL_COMMENT);
if(dealType!=0 && dealType!=1) continue;
lSize = ArraySize(profitPerMagic);
magicFound=false;
if(lSize==0)ArrayResize(profitPerMagic,(lSize/colunas)+1);
for(int j=0;j<(ArraySize(profitPerMagic)/colunas);j++)
{
if(profitPerMagic[j][0]==double(dealMagic))
{
profitPerMagic[j][1]+=_p_profit;
magicFound=true;
break;
}
}
if(!magicFound)
{
ArrayResize(profitPerMagic,(lSize/colunas)+1);
for(int j=(ArraySize(profitPerMagic)/colunas)-1;j>=0;j--)
{
profitPerMagic[j][0]=dealMagic;
profitPerMagic[j][1]=profit;
break;
}
}
profit+=_p_profit;
Print(counter+": Ativo: "+symbol+" R$ "+_p_profit+" do tipo "+dealType+" , magic: "+dealMagic," / ",dealComment);
counter++;
}
for(int i=0;i<(ArraySize(profitPerMagic)/colunas);i++)
{
Print(profitPerMagic[i][0], " / " ,profitPerMagic[i][1]);
}
return(profit);
}
//+------------------------------------------------------------------+
The easiest way is to use classes, each class extends CObject and you must implement Compare function.
First, create a structure of entering (in=true) and exiting (in=false):
struct SEvent
{
datetime m_time;
double m_price;
bool m_in;
void Init(const datetime time,const double price,const bool in)
{
m_time=time;
m_price=price;
m_in=in;
}
int Compare(SEvent &another)const
{
return int(m_time-another.m_time);
}
};
Next, create the class CDeal : public CObject
class CDeal : public CObject
{
static int getDir(string cmd)
{
if(cmd=="Sell")
return(-1);
if(cmd=="Buy")
return(1);
if(cmd=="Type" || cmd=="Balance")
return(0);
printf("%i %s: unknown cmd=|%s|",__LINE__,__FILE__,cmd);
return(0);
}
static string getSymbol(string line)
{
return StringSubstr(line,0,StringLen(line)-StringLen(InpReportSuffix))+InpSymbolSuffix;
}
public:
intX m_id;
int m_dir;
SEvent m_in;
SEvent m_out;
double m_lot;
string m_symbol;
double m_osl;
double m_otp;
CDeal(string line)
{
//2019.05.13 18:27:56;Sell;0.10;EURCADm#;1.51270;;;2019.05.14 13:36:47;1.51142;;;0.10;
string array[];
const ushort separator=(ushort)';';
int size=StringSplit(line,separator,array);
if(size<11)
{
printf("%i %s: size=%d str=%s",__LINE__,__FILE__,size,line);
m_dir=0;
return;
}
m_dir=getDir(array[1]);
m_lot=StringToDouble(array[2]);
m_symbol=getSymbol(array[3]);
m_in.Init(StringToTime(array[0]),StringToDouble(array[4]),true);
m_osl=StringLen(array[5])>0 ? StringToDouble(array[5]) : 0;
m_otp=StringLen(array[6])>0 ? StringToDouble(array[6]) : 0;
m_out.Init(StringToTime(array[7]),StringToDouble(array[8]),false);
}
~CDeal(){}
virtual int Compare(const CObject *node,const int mode=0) const
{
CDeal *another=(CDeal*)node;
if(mode==1)
{
return m_in.Compare(another.m_in);
}
else
{
return m_out.Compare(another.m_out);
}
}
virtual string toString()const
{
return StringFormat("%s;%d;%.2f;%s;%.5f;%.5f;%.5f;%s;%.5f;%s",TimeToString(m_in.m_time),m_dir,m_lot,m_symbol,
m_in.m_price,m_osl,m_otp,TimeToString(m_out.m_time),m_out.m_price,m_pnl.toString());
}
};
Then, load all CDeals from string into CArrayObj and list.Sort(1) in order to sort them by time of entry. Then loop, either from some static int cursor=0; that increments if TimeCurrent()>((CDeal*) list.At(cursor)).m_in.m_time of course keeping in mind that you may reach end of your list, or detach the element if same condition is true, and attach to another CArrayObj listOfOpenDeals. Do not forget to sort the list of existing open deals each time you add an element. Same way check whether it is time to close some deal from the list of open deals, and delete element after closing.
Altogether 300 lines of code.
I've been trying to solve a segmentation fault since yesterday, it's driving me crazy...
So I've got this program that I use to implement the sokoban game, in which a map is given, and a plan like "NSEW" is given, meaning that I want the player to move north, then south, then etc... on the map given.
map* replay(map* map_loaded, int length, char* plan){
map* new_map=move(map_loaded,plan[0]);
map* old_map=deep_copy(new_map);
for (int i=1 ; i<length ; i++){
free(new_map->p_char);
free(new_map);
new_map=move(old_map,plan[i]);
free(old_map->p_char);
free(old_map);
old_map=deep_copy(new_map);
}
free(old_map->p_char);
free(old_map);
return new_map;
}
Map is a structure defined as following :
typedef struct map map;
struct map{
int width;
int height;
char* p_char;
};
The move function does one movement ;
The deep_copy makes a deep copy of a map struct :
map* deep_copy(map* map_loaded){
map* new_map=malloc(sizeof(map));
char* p_array=map_loaded->p_char;
int width=map_loaded->width;
int height=map_loaded->height;
new_map->width=width;
new_map->height=height;
char* p_new=malloc(sizeof(char)*width*height);
for (int i=0 ; i<width*height ; i++){
p_new[i]=p_array[i];
}
new_map->p_char=p_new;
return(new_map);
}
And what happens is that if I leave the code like that, if the length chosen ( the number of movements I want the player to do) is too high (depends on the map and the movements), when executing a replay.c program :
int main(int argc, char *argv[]){
if (argc != 4) {
fprintf(stderr, "You must provide a file name or enough elements!\n");
exit(EXIT_FAILURE);
}
map* map_loaded=load(argv[1]);
int length=atoi(argv[2]);
char* plan=argv[3];
map* new_map=replay(map_loaded,length,plan);
print_map(new_map);
free(new_map->p_char);
free(new_map);
free(map_loaded->p_char);
free(map_loaded);
return 1;
}
I get a segmentation fault... But if I do :
//free(old_map->p_char);
//free(old_map);
Everything works perfect !!
I really don't understand why... The problem is if I do those free valgrind tells me I don't have as many free as allocs, which is normal...
I would really appreciate any help given...
Thanks in advance if you've been brave enough to read me until this point !
Edit :
Here is my move function ;
map* move(map* map_loaded, char dir){
int pos=Position(map_loaded);
int width=map_loaded->width;
map* new_map=deep_copy(map_loaded);
char* p_new_array=new_map->p_char;
switch(dir){
case 'N':
if (p_new_array[pos-width]=='#'){ // Si il y a un mur au dessus
return(map_loaded);
}
if ((p_new_array[pos-width]=='$' && p_new_array[pos-2*width]=='$')
||(p_new_array[pos-width]=='$' && p_new_array[pos-2*width]=='*')
||(p_new_array[pos-width]=='*' && p_new_array[pos-2*width]=='$')
||(p_new_array[pos-width]=='*' && p_new_array[pos-2*width]=='*')){ //s'il y a 2 caisses au dessus
return(map_loaded);
}
if ((p_new_array[pos-width]=='$' && p_new_array[pos-2*width]=='#') //s'il y a une caisse au niveau -1 et un mur au niveau -2
||(p_new_array[pos-width]=='*' && p_new_array[pos-2*width]=='#')){
return(map_loaded);
}
// On vérifie d'abord s'il y a une caisse à déplacer
if (p_new_array[pos-width]=='$' || p_new_array[pos-width]=='*'){
if (p_new_array[pos-2*width]=='.'){
p_new_array[pos-2*width]='*';
}
else {
p_new_array[pos-2*width]='$';
}
if (p_new_array[pos-width]=='*'){
p_new_array[pos-width]='.';
}
else{
p_new_array[pos-width]=' ';
}
}
//On change le char en position du joueur
if (p_new_array[pos]=='+'){
p_new_array[pos-width]='#';
p_new_array[pos]='.';
}
else if (p_new_array[pos-width]=='.'){
p_new_array[pos-width]='+';
p_new_array[pos]=' ';
}
else {
p_new_array[pos-width]='#';
p_new_array[pos]=' ';
}
break;
case 'S':
if (p_new_array[pos+width]=='#'){ // Si il y a un mur en dessous
return(map_loaded);
}
if ((p_new_array[pos+width]=='$' && p_new_array[pos+2*width]=='$')
||(p_new_array[pos+width]=='$' && p_new_array[pos+2*width]=='*')
||(p_new_array[pos+width]=='*' && p_new_array[pos+2*width]=='$')
||(p_new_array[pos+width]=='*' && p_new_array[pos+2*width]=='*')){//s'il y a 2 caisses au dessus
return(map_loaded);
}
if ((p_new_array[pos+width]=='$' && p_new_array[pos+2*width]=='#') //s'il y a une caisse au niveau +1 et un mur au niveau +2
||(p_new_array[pos+width]=='*' && p_new_array[pos+2*width]=='#')){
return(map_loaded);
}
// On vérifie d'abord s'il y a une caisse à déplacer
if (p_new_array[pos+width]=='$' || p_new_array[pos+width]=='*'){
if (p_new_array[pos+2*width]=='.'){
p_new_array[pos+2*width]='*';
}
else {
p_new_array[pos+2*width]='$';
}
if (p_new_array[pos+width]=='*'){
p_new_array[pos+width]='.';
}
else{
p_new_array[pos+width]=' ';
}
}
//On change le char en position du joueur
if (p_new_array[pos]=='+'){
p_new_array[pos+width]='#';
p_new_array[pos]='.';
}
else if (p_new_array[pos+width]=='.'){
p_new_array[pos+width]='+';
p_new_array[pos]=' ';
}
else {
p_new_array[pos+width]='#';
p_new_array[pos]=' ';
}
break;
case 'W':
if (p_new_array[pos-1]=='#'){ // Si il y a un mur en dessous
return(map_loaded);
}
if ((p_new_array[pos-1]=='$' && p_new_array[pos-2]=='$')
||(p_new_array[pos-1]=='$' && p_new_array[pos-2]=='*')
||(p_new_array[pos-1]=='*' && p_new_array[pos-2]=='$')
||(p_new_array[pos-1]=='*' && p_new_array[pos-2]=='*')){ //s'il y a 2 caisses à gauche
return(map_loaded);
}
if ((p_new_array[pos-1]=='$' && p_new_array[pos-2]=='#') //s'il y a une caisse au niveau -1 et un mur au niveau -2
||(p_new_array[pos-1]=='*' && p_new_array[pos-2]=='#')){
return(map_loaded);
}
// On vérifie d'abord s'il y a une caisse à déplacer
if (p_new_array[pos-1]=='$' || p_new_array[pos-1]=='*'){
if (p_new_array[pos-2]=='.'){
p_new_array[pos-2]='*';
}
else {
p_new_array[pos-2]='$';
}
if (p_new_array[pos-1]=='*'){
p_new_array[pos-1]='.';
}
else{
p_new_array[pos-1]=' ';
}
}
//On change le char en position du joueur
if (p_new_array[pos]=='+'){
p_new_array[pos-1]='#';
p_new_array[pos]='.';
}
else if (p_new_array[pos-1]=='.'){
p_new_array[pos-1]='+';
p_new_array[pos]=' ';
}
else {
p_new_array[pos-1]='#';
p_new_array[pos]=' ';
}
break;
case 'E':
if (p_new_array[pos+1]=='#') {// Si il y a un mur à droite
return(map_loaded);
}
if ((p_new_array[pos+1]=='$' && p_new_array[pos+2]=='$')
||(p_new_array[pos+1]=='$' && p_new_array[pos+2]=='*')
||(p_new_array[pos+1]=='*' && p_new_array[pos+2]=='$')
||(p_new_array[pos+1]=='*' && p_new_array[pos+2]=='*')){ //s'il y a 2 caisses à droite
return(map_loaded);
}
if ((p_new_array[pos+1]=='$' && p_new_array[pos+2]=='#') //s'il y a une caisse au niveau +1 et un mur au niveau +2
||(p_new_array[pos+1]=='*' && p_new_array[pos+2]=='#')){
return(map_loaded);
}
// On vérifie d'abord s'il y a une caisse à déplacer
if (p_new_array[pos+1]=='$' || p_new_array[pos+1]=='*'){
if (p_new_array[pos+2]=='.'){
p_new_array[pos+2]='*';
}
else {
p_new_array[pos+2]='$';
}
if (p_new_array[pos+1]=='*'){
p_new_array[pos+1]='.';
}
else{
p_new_array[pos+1]=' ';
}
}
//On change le char en position du joueur
if (p_new_array[pos]=='+'){
p_new_array[pos+1]='#';
p_new_array[pos]='.';
}
else if (p_new_array[pos+1]=='.'){
p_new_array[pos+1]='+';
p_new_array[pos]=' ';
}
else {
p_new_array[pos+1]='#';
p_new_array[pos]=' ';
}
break;
}
return(new_map);
}
And here is the load function ;
char* Array_Creator(char* filename){
FILE* p_file = fopen(filename, "r");
char* p_array = NULL;
if (p_file == NULL) {
exit(EXIT_FAILURE);
}
else{
size_t size=1;
int c;
while (getc(p_file)!=EOF) {
size++;
}
fseek(p_file,0,SEEK_SET);
while ((c=getc(p_file))!='\n' && c!=EOF) { //on se débarasse de la première ligne
size--;
}
p_array=(char*)malloc(sizeof(char)*size);
if (p_array!=NULL) { //si jamais le malloc ne fonctionne pas
for(size_t i=0; i<size-1; i++) {
p_array[i]=(char)getc(p_file);
if (p_array[i] == '\n') { // si le caractère est une nouvelle ligne, on s'en sépare
i--; // on ajuste alors la taille et l'indice
size--;
}
}
p_array[size-1]='\0';
}
fclose(p_file);
}
return p_array;
}
//La fonction Dimensions permet de récupérer les dimensions d'une map
couple Dimensions(char *p_char){
FILE *p_file = NULL;
p_file=fopen(p_char, "r");
if (p_file == NULL) {
fprintf(stderr, "Cannot read file %s!\n", p_char);
exit(EXIT_FAILURE);
}
couple dim={0,0}; //la structure couple est déf dans le loader.h
int width = 0;
int height = 0;
int fscanf_result = 0;
fscanf_result = fscanf(p_file, "%d %d\n", &width, &height);
if (fscanf_result != 2) {
fprintf(stderr, "First line is not syntactically correct!\n");
exit(EXIT_FAILURE);
}
dim.x=width;
dim.y=height;
fclose(p_file);
return dim;
}
//La fonction Load est celle demandée et permettant de charger une carte ; elle utilise Dimensions et Array_Creator
map* load(char *filename){
map* map_loaded=malloc(sizeof(map)); //on alloue dynamiquement la map
//Dans un premier temps on récupère les dimensions
couple map_dim={0,0};
map_dim=Dimensions(filename);
map_loaded->width=map_dim.x;
map_loaded->height=map_dim.y;
//Dans un second temps on définit le tableau 1D contenant l'ensemble des éléments de la map
char* p_char=Array_Creator(filename);
map_loaded->p_char=p_char;
return map_loaded;
}
The command line is, for example :
./replay ./data/soko.in 4 7"NSWSESNWW"
In the move function, should change all
return(map_loaded); => return(new_map);
It will map_loaded to be freed twice when the move function returns map_loaded
Code analysis
map *replay(map *map_loaded, int length, char *plan)
{
map *new_map = move(map_loaded, plan[0]); // [2] set new_map to map_loaded
map *old_map = deep_copy(new_map);
for (int i = 1 ; i < length ; i++) {
free(new_map->p_char);
free(new_map); // [3] new_map be freed,
// equivalent map_loaded be freed
new_map = move(old_map, plan[i]);
...
}
...
return new_map;
}
int main(int argc, char *argv[])
...
map *map_loaded = load(argv[1]); // [1] map_loaded be malloc
...
map *new_map = replay(map_loaded, length, plan);
...
free(map_loaded->p_char);
free(map_loaded); // [4] map_loaded be freed
...
}
I'm creating a menu in my game (available when I hit escape on the keyboard)
But the black background created with SDL_Rect and the text aren't showing and I don't understand why.
When I run my program I can change the background images by pressing on the arrows (up, down, left and right), and when I hit esc, i can't do anything until I hit esc another time, and then I can continue changing the background color with the arrows on my keyboard.
Does anybody can help me with this?
#include <SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <SDL_image.h>
#include <SDL2/SDL_ttf.h>
#define CHOICEMENU 2
void errorMessage(const char *message);
void errorMessageImg(const char *message);
void errorMessageTtf(const char *message);
int printTextTtf(SDL_Surface* window, TTF_Font* mainFont, const char* text);
int displayMenu(SDL_Surface* window, TTF_Font* font);
int main( int argc, char **argv)
{
//Pointeurs de la SDL :
SDL_Window *window = NULL;
SDL_Surface *windowSurface = NULL;
SDL_Surface *image1,*image2, *image3, *image4 = NULL;
SDL_Surface *currentImage = NULL;
SDL_Surface *icon = NULL;
SDL_Renderer *renderer = NULL;
int menu;
int running;
TTF_Init(); //initialisation des textes
TTF_Font *mainFont = NULL;
mainFont = TTF_OpenFont("couriernew.ttf",30);
icon = IMG_Load("img/flask.png");
SDL_SetWindowIcon(window,icon);
if(SDL_Init(SDL_INIT_VIDEO) != 0){ //retourne 0 si Ok
errorMessage("Erreur lors de la creation de la fenêtre et du rendu");
}
window = SDL_CreateWindow("Jeu Antoine et Robin", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
windowSurface = SDL_GetWindowSurface(window);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED |
SDL_RENDERER_PRESENTVSYNC);
//texture = SDL_LoadBMP("ici.bmp");
image1 = SDL_LoadBMP("img/image1.bmp");
if(image1 == NULL){
SDL_DestroyWindow(window);
errorMessage("Impossible de charger l'image 1");
}
image2 = SDL_LoadBMP("img/image2.bmp");
if(image2 == NULL){
SDL_DestroyWindow(window);
errorMessage("Impossible de charger l'image 2");
}
image3 = SDL_LoadBMP("img/image3.bmp");
if(image3 == NULL){
SDL_DestroyWindow(window);
errorMessage("Impossible de charger l'image 3");
}
image4 = SDL_LoadBMP("img/image4.bmp");
if(image4 == NULL){
SDL_DestroyWindow(window);
errorMessage("Impossible de charger l'image 4");
}
currentImage = image1;
int isRunning = 1;
SDL_Event ev;
while(isRunning == 1){
while(SDL_PollEvent(&ev) != 0 ){
if(ev.type == SDL_QUIT){
isRunning = false;
}else if(ev.type == SDL_KEYDOWN){
switch(ev.key.keysym.sym){
case SDLK_UP:
currentImage = image1;
break;
case SDLK_RIGHT:
currentImage = image2;
break;
case SDLK_LEFT:
currentImage = image3;
break;
case SDLK_DOWN:
currentImage = image4;
break;
case SDL_QUIT:
isRunning = 0;
break;
case SDLK_ESCAPE:
menu = displayMenu(windowSurface,mainFont);
if(menu == 1){
isRunning = false;
}
break;
}
}
}
SDL_BlitSurface(currentImage, NULL, windowSurface, NULL);
SDL_UpdateWindowSurface(window);
}
TTF_CloseFont(mainFont);
SDL_FreeSurface(image1);
SDL_FreeSurface(image2);
SDL_FreeSurface(image3);
SDL_FreeSurface(image4);
SDL_DestroyWindow(window);
SDL_FreeSurface(icon);
SDL_DestroyRenderer(renderer);
currentImage = image1 = image2 = image3 = NULL;
window = NULL;
SDL_Quit();
return 0;
}
int displayMenu(SDL_Surface* window, TTF_Font* font){
int x,y; // coordonées de la souris
int i;
int nMenu = CHOICEMENU; //nb de choix
const char* choice[CHOICEMENU] = {"Continuer","Quitter"};
SDL_Surface* menus[CHOICEMENU]; // surface des menus
int selected[CHOICEMENU]={0,0}; // 0 car aucun selectionné pour le moment
SDL_Color colorMenu[2]={{127,122,204},{49,100,226}};
menus[0] = TTF_RenderText_Solid(font, choice[0], colorMenu[0]);
menus[1] = TTF_RenderText_Solid(font, choice[1], colorMenu[1]);
SDL_Rect pos[CHOICEMENU];
pos[0].x = window->clip_rect.w/2 /*= centre */ - menus[0]->clip_rect.w/2;
pos[0].y = window->clip_rect.h/2 - menus[0]->clip_rect.h;
pos[1].x = window->clip_rect.w/2 - menus[0]->clip_rect.w/2;
pos[1].y = window->clip_rect.h/2 + menus[0]->clip_rect.h;
SDL_FillRect(window,&window->clip_rect,SDL_MapRGB(window-
>format,0x00,0x00,0x00));
SDL_Event ev;
while(1){
while(SDL_PollEvent(&ev)){
switch(ev.type){
case SDL_QUIT:
for(i = 0; i < CHOICEMENU ; i++){
SDL_FreeSurface(menus[i]);
}
return 1;
case SDL_MOUSEMOTION: // coordonée souris
x = ev.motion.x;
y = ev.motion.y;
for(i = 0; i < CHOICEMENU; i++){
if(x >= pos[i].x && x<= pos[i].x+pos[i].w && y>=pos[i].y &&
y<=pos[i].y+pos[i].h){
if(!selected[i]){
selected[i] = 1;
SDL_FreeSurface(menus[i]); // on suppr l'ancienne
surface
menus[i] = TTF_RenderText_Solid(font, choice[i],
colorMenu[1]);
} else {
if(selected[i]){
selected[i] = 0;
SDL_FreeSurface(menus[i]); // on suppr
l'ancienne surface
menus[i] = TTF_RenderText_Solid(font, choice[i],
colorMenu[0]);
}
}
}
case SDL_MOUSEBUTTONDOWN: //si qqn a cliquer sur la souris :
x = ev.button.x;
y = ev.button.y;
for (i = 0; i < CHOICEMENU; i+=1){
if(x >= pos[i].x && x<= pos[i].x+pos[i].w && y>=pos[i].y &&
y<=pos[i].y+pos[i].h){
for(i = 0 ;i < CHOICEMENU; i++){
SDL_FreeSurface(menus[i]);
}
return i; // On retourne la valeur actuelle : ex : si je
clique sur "continue" ça return 1
}
}
break;
case SDL_KEYDOWN:
if(ev.key.keysym.sym == SDLK_ESCAPE){
for(i = 0 ;i < CHOICEMENU; i++){
SDL_FreeSurface(menus[i]);
}
return 0;
}
}
}
for(i = 0; i < CHOICEMENU; i+=1){
SDL_BlitSurface(menus[i],NULL,window,&pos[i]);
}
}
}
}
Im using codeblocks and i have install the librares already and there are no error there...
When i build the project, the compiler says it has no errors and when i run it it just pops up a windows and inside its just black, and its suppose to appear the words "Hola Mundo..." i got ariblk.ttf in the project folder...
#include <stdio.h>
#include <stdlib.h>
#include <SDL.h>
#include "SDL_ttf.h"
int main(int argc, char *argv[]) {
SDL_Color bgcolor,fgcolor;
SDL_Rect rectangulo;
SDL_Surface *screen,*ttext;
TTF_Font *fuente;
const char texto[14]="Hola Mundo...";
char msg[14];
SDL_Event event;
int done = 0;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("No se pudo iniciar SDL: %s\n",SDL_GetError());
return 1;
}
screen = SDL_SetVideoMode(640,480,24,SDL_HWSURFACE|SDL_DOUBLEBUF);
if (screen == NULL) {
printf("No se puede inicializar el modo gráfico: %s\n",SDL_GetError());
return 1;
}
atexit(SDL_Quit);
if (TTF_Init() < 0) {
printf("No se pudo iniciar SDL_ttf: %s\n",SDL_GetError());
return 1;
}
atexit(TTF_Quit);
fuente = TTF_OpenFont("ariblk.ttf",20);
if(fuente == NULL)
{
printf("No se pudo cargar fuente %s",TTF_GetError());
}
fgcolor.r=200;
fgcolor.g=200;
fgcolor.b=10;
bgcolor.r=255;
bgcolor.g=0;
bgcolor.b=0;
sprintf(msg,"%s",texto);
ttext = TTF_RenderText_Shaded(fuente,msg,fgcolor,bgcolor);
rectangulo.y=100;
rectangulo.x=100;
rectangulo.w=ttext->w;
rectangulo.h=ttext->h;
SDL_SetColorKey(ttext,SDL_SRCCOLORKEY|SDL_RLEACCEL, SDL_MapRGB(ttext->format,255,0,0));
SDL_BlitSurface(ttext,NULL,screen,&rectangulo);
TTF_CloseFont(fuente);
SDL_FreeSurface(ttext);
while(done == 0)
{
while ( SDL_PollEvent(&event) )
{
if ( event.type == SDL_KEYDOWN )
done = 1;
}
}
return 0;
}
You need to call SDL_Flip to make your changes visible on the screen. Try adding SDL_Flip(screen); after SDL_BlitSurface in your source code.
Hope this helps!