|
Getting artefact when loading image |
Francis Langlais
Member #15,985
June 2015
|
I'm trying to load an image for my game. Each robot is a structure and I store the image in it. What happen when the image is drawn is sometimes it draw some artefact over the image and sometimes it doesn't and it's completely random. In the first image attached, only the blue robot doesn't have artefact and in the second one, the pink one doesn't have it either. Those 2 frame are from different run of the program and the 4 robots are the same. I was just wondering if storing an ALLEGRO_BITMAP into a structure is a good idea or this could be the source of my problem? PS: I don't know how to link image directly in the post so I attached it. |
RPG Hacker
Member #12,492
January 2011
|
It's hard to help you without having the code that produces this output. So if I had to guess from the screenshots, I'd say it looks like you're trying to draw bitmaps that weren't properly initialized. These pink-ish garbage sprites above the robots look like you were trying to draw bitmaps with random data in them. Or, actually, looking at the garbage sprites... it also looks like it could be actual sprites that for some reason have the wrong dimensions, so that the pixels are at the wrong locations. In any case, as I said, without any code it's really hard to help here.
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
You could be drawing destroyed copies of bitmaps depending on your code. What do you do with your stored ALLEGRO_BITMAP*? Remember it's just a pointer but if you're destroying it in your destructor and you make copies of your struct then the original will be destroyed and you will be left with a dangling pointer. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Francis Langlais
Member #15,985
June 2015
|
Here's the code (it's scattered around my program) : How I create the Robot: void BENDERBOT(ROBOTCOLORS color) { RegisterRobot("Bender", color, &BenderActions, &PimpOutBender, "resources\\images\\basic_robot.bmp", -1, -1, -1); }
1void RegisterRobot(char *robotName, ROBOTCOLORS color,
2 void (*robotActions)(int), void (*configureRobot)(void),
3 char *customImage, int x, int y, float heading) {
4 int i, robotNumber;
5 ROBOT newRobot;
6
7 if (theGame.state != GS_SETUP)
8 AbortOnError(
9 "Call made to RegisterRobot() when game is not in setup state."
10 "\nProgram will end.");
11
12 robotNumber = SizeLL(robotList);
13 if (robotNumber == MAX_ROBOTS)
14 AbortOnError("RegisterRobot() Attempted to add too many robots.\n"
15 "Program will end.");
16
17 newRobot.ActionsFunction = robotActions;
18
19 switch (color) {
20 case ROBOT_RED:
21 newRobot.color = al_map_rgb(255, 0, 0);
22 break;
23 case ROBOT_GREEN:
24 newRobot.color = al_map_rgb(0, 255, 0);
25 break;
26 case ROBOT_BLUE:
27 newRobot.color = al_map_rgb(0, 0, 255);
28 break;
29 case ROBOT_YELLOW:
30 newRobot.color = al_map_rgb(255, 255, 0);
31 break;
32 case ROBOT_PURPLE:
33 newRobot.color = al_map_rgb(255, 0, 240);
34 break;
35 case ROBOT_TURQUOISE:
36 newRobot.color = al_map_rgb(0, 255, 255);
37 break;
38 case ROBOT_WHITE:
39 default:
40 newRobot.color = al_map_rgb(255, 255, 255);
41 }
42 if (HasNullCharacter(robotName, MAX_NAME_LEN)) {
43 newRobot.name = malloc(sizeof(char) * strlen(robotName));
44 strcpy(newRobot.name, robotName);
45 newRobot.number = robotNumber;
46 } else
47 AbortOnError("RegisterRobot() was passed a robot name exceeding "
48 "MAX_NAME_LEN.\nProgram will end.");
49
50 //Set starting speed values
51 newRobot.leftTreadSpeed = 0;
52 newRobot.rightTreadSpeed = 0;
53 newRobot.impulseHeading = 0;
54 newRobot.impulseSpeed = 0;
55 newRobot.turboTime = 0;
56
57 //Configure the sensors.
58 newRobot.bumped = BUMP_NONE;
59 for (i = 0; i < MAX_SENSORS; i++) {
60 newRobot.sensorArray[i].type = SENSOR_NONE;
61 newRobot.sensorArray[i].image = NULL;
62 }
63
64 //Configure the laser.
65 newRobot.weaponArray[LASER_PORT].type = WEAPON_LASER;
66 newRobot.weaponArray[LASER_PORT].maxAngle = LASER_MAX_ANGLE;
67 newRobot.weaponArray[LASER_PORT].minEnergy = MIN_LASER_ENERGY;
68 newRobot.weaponArray[LASER_PORT].maxEnergy = MAX_LASER_ENERGY;
69 newRobot.weaponArray[LASER_PORT].bonusEnergy = LASER_ENERGY_BONUS;
70 newRobot.weaponArray[LASER_PORT].splashRange = LASER_SPLASH_RANGE;
71 newRobot.weaponArray[LASER_PORT].splashDamage = LASER_SPLASH_DAMAGE;
72 newRobot.weaponArray[LASER_PORT].speed = LASER_SPEED;
73 newRobot.weaponArray[LASER_PORT].bumpValue = BUMP_LASER;
74 newRobot.weaponArray[LASER_PORT].firingSound = SND_LASER_FIRE;
75 newRobot.weaponArray[LASER_PORT].impactSound = SND_LASER_HIT;
76
77 //Configure the missiles.
78 newRobot.weaponArray[MISSILE_PORT].type = WEAPON_MISSILE;
79 newRobot.weaponArray[MISSILE_PORT].maxAngle = MISSILE_MAX_ANGLE;
80 newRobot.weaponArray[MISSILE_PORT].minEnergy = MIN_MISSILE_ENERGY;
81 newRobot.weaponArray[MISSILE_PORT].maxEnergy = MAX_MISSILE_ENERGY;
82 newRobot.weaponArray[MISSILE_PORT].bonusEnergy = MISSILE_ENERGY_BONUS;
83 newRobot.weaponArray[MISSILE_PORT].splashRange = MISSILE_SPLASH_RANGE;
84 newRobot.weaponArray[MISSILE_PORT].splashDamage = MISSILE_SPLASH_DAMAGE;
85 newRobot.weaponArray[MISSILE_PORT].speed = MISSILE_SPEED;
86 newRobot.weaponArray[MISSILE_PORT].bumpValue = BUMP_MISSILE;
87 newRobot.weaponArray[MISSILE_PORT].firingSound = SND_MISSILE_FIRE;
88 newRobot.weaponArray[MISSILE_PORT].impactSound = SND_MISSILE_HIT;
89
90 for (i = 0; i < MAX_WEAPONS; i++) {
91 newRobot.weaponArray[i].chargeRate = 0;
92 newRobot.weaponArray[i].chargeEnergy = 0;
93 }
94
95 //Set starting energy priorites in same order as SYSTEMS declaration.
96 for (i = 0; i < NUM_ENERGY_SYSTEMS; i++)
97 newRobot.energyPriorities[i] = (SYSTEM) i;
98
99 //Set initial energy values. Weapons were done in the weapons section.
100 newRobot.shields = START_SHIELD_ENERGY;
101 newRobot.shieldChargeRate = 0;
102
103 //Set structure-related values
104 newRobot.generatorStructure = MAX_GENERATOR_STRUCTURE;
105
106 //Robot has no damage to be applied at start.
107 newRobot.damageBank = 0;
108
109 //Load the robot's graphic, if required. There is no error checking here as
110 //if newRobot.graphic is NULL, the graphics routines will simply use the
111 //default robot graphic to render the robot.
112 newRobot.graphic = NULL;
113 if (customImage != NULL){
114 newRobot.graphic = al_load_bitmap(customImage);
115 al_convert_mask_to_alpha(newRobot.graphic, al_map_rgb(255, 0, 255));
116 }
117
118 //Create the robot's bitmap.
119 newRobot.shield = al_create_bitmap(SHIELD_BMP_SZ, SHIELD_BMP_SZ);
120 newRobot.image = al_create_bitmap(SHIELD_BMP_SZ, SHIELD_BMP_SZ);
121 al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
122 if (newRobot.image == NULL || newRobot.shield == NULL)
123 AbortOnError("RegisterRobot() failed to create robot image.\n"
124 "Program will end.");
125
126 strcpy(newRobot.statusMessage, ""); //No status message at start.
127
128 newRobot.mailBox = ConsLL(); //Create the robot's mailbox.
129
130 InsLastLL(robotList, newRobot); //Put robot on end of the list.
131 curRobot = LastElmLL(robotList); //Record current robot for configuration.
132
133 //Set robot starting location. This is done only after insertion into the
134 //list because ChooseRandomLocation() requires the list to have robots in it.
135 if (x < 0 || y < 0)
136 ChooseRandomLocation(curRobot);
137 else {
138 curRobot->x = x;
139 curRobot->y = y;
140 }
141 if (heading < 0)
142 curRobot->heading = GetRandomNumber(360);
143 else
144 curRobot->heading = heading;
145
146 configureRobot(); //Call user's configuration function.
147}
The image is stored in newRobot.graphic at the 112-115th line. Also note that if, when I call the RegistewrRobot and customImage = NULL the program gives it the default image and it work fine but if I give it the path to the default image it gives me artefact. Then this is when I draw the robot : 1void DrawRobotBitmaps(t_LL listOfRobots) {
2 float shieldCenterX, shieldCenterY;
3 float drawAngle, modifier;
4 ROBOT *robot;
5 ALLEGRO_BITMAP *robotGraphic;
6 ALLEGRO_BITMAP *temp;
7
8 ForeachLL_M(listOfRobots, robot)
9 {
10 temp = al_create_bitmap(SHIELD_BMP_SZ, SHIELD_BMP_SZ);
11
12 clearBitmap(temp);
13 clearBitmap(robot->image);
14
15 shieldCenterX = al_get_bitmap_width(temp) / 2; //All robot's shields are same size,
16 shieldCenterY = al_get_bitmap_height(temp) / 2; //so calculate center point here.
17
18 drawAngle = 90 - robot->heading; //Convert "math" angle to screen "heading"
19 if (drawAngle < 0) //angle as rotate_sprite is in compass
20 drawAngle = drawAngle + 360; //coords and make positive.
21 drawAngle = drawAngle * PI / 180; //Convert from degrees to radian.
22
23 modifier = robot->shields / MAX_SHIELD_ENERGY;
24
25 if (robot->graphic != NULL){
26 robotGraphic = robot->graphic;
27 } else {
28 robotGraphic = robotImg;
29 }
30
31 al_set_target_bitmap(temp);
32 al_draw_bitmap(robotGraphic,
33 al_get_bitmap_width(robot->image) / 2
34 - al_get_bitmap_width(robotGraphic) / 2,
35 al_get_bitmap_height(robot->image) / 2
36 - al_get_bitmap_height(robotGraphic) / 2, 0);
37 al_set_target_bitmap(robot->image);
38 al_draw_rotated_bitmap(temp, shieldCenterX, shieldCenterY,
39 SHIELD_BMP_SZ / 2, SHIELD_BMP_SZ / 2, drawAngle, 0);
40 al_draw_tinted_bitmap(robot->shield,
41 al_map_rgba_f(1 * modifier, 1 * modifier, 1 * modifier,
42 modifier), 0, 0, 0);
43 }
44
45 al_destroy_bitmap(temp);
46}
And this is when I destroy the bitmap : 1void EndCompetition() {
2 int i;
3 ROBOT *tempRobot, *nextRobot;
4 WEAPON *tempWeapon, *nextWeapon;
5
6 //Move the dead robots back into the main list for deletion.
7 //deadRobotList should be empty after this loop has finished.
8 while (!IsEmptyLL(deadRobotList))
9 LinkAftLL(LastElmLL(robotList), UnlinkLL(FirstElmLL(deadRobotList)));
10
11 //Now iterate through each robot, cleaning up allocated memory
12 //and, when all memory is cleaned up, remove each one from the list.
13 SafeForeachLL_M(robotList, tempRobot, nextRobot)
14 //Has to be "safe" as
15 { //list elements will be
16 nextRobot = NextElmLL(tempRobot); //deleted during the
17 for (i = 0; i < MAX_SENSORS; i++) //iteration.
18 if (tempRobot->sensorArray[i].image != NULL)
19 al_destroy_bitmap(tempRobot->sensorArray[i].image); //Free sensor images.
20
21 if (tempRobot->graphic != NULL)
22 al_destroy_bitmap(tempRobot->graphic); //Free custom images.
23 al_destroy_bitmap(tempRobot->image); //Free robot bitmaps.
24 free(tempRobot->name); //Free robot name strings.
25
26 DestLL(tempRobot->mailBox); //Remove all messages.
27
28 DelElmLL(tempRobot); //Delete the robot from the list.
29 }
30
31 //Now clean up the weapon list, deleting each weapon.
32 SafeForeachLL_M(weaponList, tempWeapon, nextWeapon)
33 {
34 nextWeapon = NextElmLL(tempWeapon);
35 if (tempWeapon->image != NULL)
36 al_destroy_bitmap(tempWeapon->image); //Free weapon images.
37 DelElmLL(tempWeapon); //Delete the weapon.
38 }
39
40 if (IsEmptyLL(robotList) && IsEmptyLL(deadRobotList)
41 && IsEmptyLL(weaponList)) {
42 DestLL(robotList);
43 DestLL(deadRobotList);
44 DestLL(weaponList);
45 } else {
46 DestLL(robotList);
47 DestLL(deadRobotList);
48 DestLL(weaponList);
49 AbortOnError(
50 "EndCompetition() discovered one of the main linked lists was "
51 "not empty before deletion.\n"
52 "Program will now end.");
53 }
54
55 //Delete the sounds.
56 for (i = 0; i < NUM_SOUNDS; i++)
57 if (theGame.sounds[i] != NULL)
58 al_destroy_sample(theGame.sounds[i]);
59
60 DeInitGraphics();
61
62}
The bitmap is destroyed at line 21-22th line. Those are the only action I take on the robot.graphic. Finally here is the action order of my game loop : 1void Fight(ALLEGRO_DISPLAY *display) {
2
3 calcsUntilOrders++;
4
5 UpdateEnergySystems(robotList); //Do first so we know what
6 //systems are powered.
7
8 MoveRobots(robotList);
9 DrawRobotBitmaps(robotList);
10 CheckRobotCollisions(&theGame, robotList);
11
12 MoveWeapons(weaponList);
13 CheckWeaponCollisions(&theGame, robotList, weaponList);
14
15 //Now that collisions are
16 ApplyDamage(&theGame, robotList, deadRobotList); //done and weapons have
17 //hit, we apply damage.
18
19 DrawSensorBitmaps(robotList); //Need to draw BEFORE data is
20 //updated because bimaps are
21 //used in collision detection.
22 UpdateSensorData(robotList);
23
24 UpdateParticles();
25
26 calcsCompleted++;
27
28 if (calcsUntilOrders == ORDER_FREQ) {
29 calcsUntilOrders = 0;
30 ForeachLL_M(robotList, curRobot)
31 curRobot->ActionsFunction(TURN_TIME);
32 }
33
34// if (theGame.useSounds)
35// PlaySounds(&theGame);
36
37}
@Edgar Reynaldo The fact that if I load the bitmap using a path in the RegisterRobot or using NULL to load the same bitmap doesn't give me the same result feel strange to me. |
RPG Hacker
Member #12,492
January 2011
|
Francis Langlais said: 119newRobot.shield = al_create_bitmap(SHIELD_BMP_SZ, SHIELD_BMP_SZ);
120newRobot.image = al_create_bitmap(SHIELD_BMP_SZ, SHIELD_BMP_SZ);
121al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
I see this is where you create "shield", but where do you fill its contents? If you just create a bitmap without filling it, it will only contain garbage. Francis Langlais said: temp = al_create_bitmap(SHIELD_BMP_SZ, SHIELD_BMP_SZ); Is there a reason for creating and destroying the bitmap in every draw call? Creating bitmaps can be slow and shouldn't be done every frame unless absolutely necessary. Since you're using constant sizes here, recreating the bitmap every frame isn't necessary. Just create the image onces with the robot and destroy it once the robot is destroyed.
|
Francis Langlais
Member #15,985
June 2015
|
Yeah I found out that the shield was doing the artefact and I will simply remove the pre-rendered shield. I did that because I had a FPS problem which had nothing to do with it. The memory thing was because I wanted to draw my particles (which use al_put_pixel) on it but Edgar told me to lock/unlock my bitmap instead. Yes I will fix this creating/destroying bitmap thing. Thank you for your help! |
|