From: Brian G. <ge...@us...> - 2006-04-19 14:29:33
|
Update of /cvsroot/playerstage/code/player/server/drivers/map In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3490/server/drivers/map Modified Files: Tag: release-2-0-patches Makefile.am mapcspace.cc mapscale.cc Added Files: Tag: release-2-0-patches maptransform.cc maptransform.h Log Message: backported map driver updates and v4lcapture.c fix Index: Makefile.am =================================================================== RCS file: /cvsroot/playerstage/code/player/server/drivers/map/Makefile.am,v retrieving revision 1.9 retrieving revision 1.9.4.1 diff -C2 -d -r1.9 -r1.9.4.1 *** Makefile.am 5 Oct 2005 16:55:20 -0000 1.9 --- Makefile.am 19 Apr 2006 21:29:28 -0000 1.9.4.1 *************** *** 17,20 **** libmapfile_la_SOURCES = mapfile.cc libvmapfile_la_SOURCES = vmapfile.cc ! libmapcspace_la_SOURCES = mapcspace.cc ! libmapscale_la_SOURCES = mapscale.cc --- 17,20 ---- libmapfile_la_SOURCES = mapfile.cc libvmapfile_la_SOURCES = vmapfile.cc ! libmapcspace_la_SOURCES = maptransform.cc mapcspace.cc ! libmapscale_la_SOURCES = maptransform.cc mapscale.cc Index: mapcspace.cc =================================================================== RCS file: /cvsroot/playerstage/code/player/server/drivers/map/mapcspace.cc,v retrieving revision 1.11 retrieving revision 1.11.2.1 diff -C2 -d -r1.11 -r1.11.2.1 *** mapcspace.cc 23 Feb 2006 18:54:54 -0000 1.11 --- mapcspace.cc 19 Apr 2006 21:29:28 -0000 1.11.2.1 *************** *** 97,119 **** /** @} */ ! #include <sys/types.h> // required by Darwin ! #include <netinet/in.h> ! #include <stdlib.h> ! #include <string.h> ! #include <math.h> ! ! #include <player.h> ! #include <drivertable.h> ! #include <driver.h> ! #include <devicetable.h> ! #include <error.h> ! ! // compute linear index for given map coords ! #define MAP_IDX(mf, i, j) ((mf->size_x) * (j) + (i)) ! ! // check that given coords are valid (i.e., on the map) ! #define MAP_VALID(mf, i, j) ((i >= 0) && (i < mf->size_x) && (j >= 0) && (j < mf->size_y)) ! ! extern int global_playerport; typedef enum --- 97,101 ---- /** @} */ ! #include "maptransform.h" typedef enum *************** *** 122,154 **** } robot_shape_t; ! class MapCspace : public Driver { private: - double resolution; - unsigned int size_x, size_y; - char* mapdata; - player_device_id_t map_id; robot_shape_t robot_shape; double robot_radius; - // get the map from the underlying map device - int GetMap(); // convolve the map with a circular robot to produce the cspace ! int CreateCspaceCircle(); - // Handle map info request - void HandleGetMapInfo(void *client, void *request, int len); - // Handle map data request - void HandleGetMapData(void *client, void *request, int len); public: ! MapCspace(ConfigFile* cf, int section, player_device_id_t id, robot_shape_t shape, double radius); ~MapCspace(); - int ProcessMessage(ClientData * client, player_msghdr * hdr, uint8_t * data, uint8_t * resp_data, size_t * resp_len); - int Setup(); - int Shutdown(); - /* int PutConfig(player_device_id_t id, void *client, - void* src, size_t len, - struct timeval* timestamp);*/ }; --- 104,120 ---- } robot_shape_t; ! class MapCspace : public MapTransform { private: robot_shape_t robot_shape; double robot_radius; // convolve the map with a circular robot to produce the cspace ! int Transform(); public: ! MapCspace(ConfigFile* cf, int section); ~MapCspace(); }; *************** *** 156,192 **** MapCspace_Init(ConfigFile* cf, int section) { ! const char* shapestring; ! double radius; ! robot_shape_t shape; ! player_device_id_t map_id; ! ! // Must have an input map ! if (cf->ReadDeviceId(&map_id, section, "requires", ! PLAYER_MAP_CODE, -1, NULL) != 0) ! { ! PLAYER_ERROR("must specify input map"); ! return(NULL); ! } ! if((radius = cf->ReadLength(section,"robot_radius",-1.0)) < 0) ! { ! PLAYER_ERROR("must specify positive robot radius"); ! return(NULL); ! } ! if(!(shapestring = cf->ReadString(section,"robot_shape",NULL))) ! { ! PLAYER_ERROR("must specify robot shape"); ! return(NULL); ! } ! if(!strcmp(shapestring,"circle")) ! { ! shape = CIRCLE; ! } ! else ! { ! PLAYER_ERROR1("unknown robot shape \"%s\"", shapestring); ! return(NULL); ! } ! ! return((Driver*)(new MapCspace(cf, section, map_id, shape, radius))); } --- 122,126 ---- MapCspace_Init(ConfigFile* cf, int section) { ! return((Driver*)(new MapCspace(cf, section))); } *************** *** 200,372 **** // this one has no data or commands, just configs ! MapCspace::MapCspace(ConfigFile* cf, int section, ! player_device_id_t id, robot_shape_t shape, double radius) ! : Driver(cf, section, true, PLAYER_MSGQUEUE_DEFAULT_MAXLEN, PLAYER_MAP_CODE, PLAYER_READ_MODE) ! { ! this->mapdata = NULL; ! this->size_x = this->size_y = 0; ! this->map_id = id; ! this->robot_shape = shape; ! this->robot_radius = radius; ! } ! ! MapCspace::~MapCspace() ! { ! } ! ! int ! MapCspace::Setup() ! { ! if(this->GetMap() < 0) ! return(-1); ! if(this->CreateCspaceCircle() < 0) ! return(-1); ! ! return(0); ! } ! ! // get the map from the underlying map device ! // TODO: should Unsubscribe from the map on error returns in the function ! int ! MapCspace::GetMap() { ! Driver* mapdevice; ! ! // Subscribe to the map device ! if(!(mapdevice = SubscribeInternal(map_id))) { ! PLAYER_ERROR("unable to locate suitable map device"); ! return(-1); } ! /* if(mapdevice == this) { ! PLAYER_ERROR("tried to subscribe to self; specify a *different* map index"); ! return(-1); } ! if(mapdevice->Subscribe(map_id) != 0) ! { ! PLAYER_ERROR("unable to subscribe to map device"); ! return(-1); ! }*/ ! ! printf("MapCspace: Loading map from map:%d...\n", this->map_id.index); ! fflush(NULL); ! ! // Fill in the map structure ! ! // first, get the map info ! //int replen; ! unsigned short reptype; ! player_map_info_t info; ! //struct timeval ts; ! /* info.subtype = PLAYER_MAP_GET_INFO_REQ; ! if((replen = mapdevice->Request(map_id, this, ! &info, sizeof(info.subtype), NULL, ! &reptype, &info, sizeof(info), &ts)) == 0) ! { ! PLAYER_ERROR("failed to get map info"); ! return(-1); ! }*/ ! size_t resp_size = sizeof(info); ! reptype = mapdevice->ProcessMessage(PLAYER_MSGTYPE_REQ, PLAYER_MAP_GET_INFO, ! map_id, 0, (uint8_t *)&info, (uint8_t *)&info, &resp_size); ! ! if (reptype != PLAYER_MSGTYPE_RESP_ACK) { ! PLAYER_ERROR("failed to get map info"); ! return(-1); } ! ! // copy in the map info ! this->resolution = 1/(ntohl(info.scale) / 1e3); ! this->size_x = ntohl(info.width); ! this->size_y = ntohl(info.height); ! ! // allocate space for map cells ! this->mapdata = (char*)malloc(sizeof(char) * ! this->size_x * ! this->size_y); ! ! assert(this->mapdata); ! ! // now, get the map data ! player_map_data_t data_req; ! unsigned int reqlen; ! unsigned int i,j; ! unsigned int oi,oj; ! unsigned int sx,sy; ! unsigned int si,sj; ! ! //data_req.subtype = PLAYER_MAP_GET_DATA_REQ; ! ! // Tile size ! sy = sx = (int)sqrt(sizeof(data_req.data)); ! assert(sx * sy < (int)sizeof(data_req.data)); ! oi=oj=0; ! while((oi < this->size_x) && (oj < this->size_y)) { ! si = MIN(sx, this->size_x - oi); ! sj = MIN(sy, this->size_y - oj); ! ! data_req.col = htonl(oi); ! data_req.row = htonl(oj); ! data_req.width = htonl(si); ! data_req.height = htonl(sj); ! ! reqlen = sizeof(data_req) - sizeof(data_req.data); ! resp_size = sizeof(data_req); ! reptype = mapdevice->ProcessMessage(PLAYER_MSGTYPE_REQ, PLAYER_MAP_GET_DATA, ! map_id, reqlen, (uint8_t *)&data_req, (uint8_t *)&data_req, &resp_size); ! ! ! ! /* if((replen = mapdevice->Request(map_id, this, ! &data_req, reqlen, NULL, ! &reptype, &data_req, ! sizeof(data_req), &ts)) == 0)*/ ! if (reptype != PLAYER_MSGTYPE_RESP_ACK) ! { ! PLAYER_ERROR("failed to get map info"); ! return(-1); ! } ! else if(resp_size != (reqlen + si * sj)) ! { ! PLAYER_ERROR2("got less map data than expected (%d != %d)", ! resp_size, reqlen + si*sj); ! return(-1); ! } ! ! // copy the map data ! for(j=0;j<sj;j++) ! { ! for(i=0;i<si;i++) ! { ! this->mapdata[MAP_IDX(this,oi+i,oj+j)] = data_req.data[j*si + i]; ! } ! } ! ! oi += si; ! if(oi >= this->size_x) ! { ! oi = 0; ! oj += sj; ! } } ! // we're done with the map device now ! UnsubscribeInternal(map_id); ! ! // Read data ! puts("Done."); ! printf("MapCspace read a %d X %d map, at %.3f m/pix\n", ! this->size_x, this->size_y, this->resolution); ! return(0); } // convolve the map with a circular robot to produce the cspace int ! MapCspace::CreateCspaceCircle() { unsigned int i,j; --- 134,172 ---- // this one has no data or commands, just configs ! MapCspace::MapCspace(ConfigFile* cf, int section) ! : MapTransform(cf, section) { ! const char* shapestring; ! if((robot_radius = cf->ReadLength(section,"robot_radius",-1.0)) < 0) { ! PLAYER_ERROR("must specify positive robot radius"); ! return; } ! if(!(shapestring = cf->ReadString(section,"robot_shape",NULL))) { ! PLAYER_ERROR("must specify robot shape"); ! return; } ! if(!strcmp(shapestring,"circle")) { ! robot_shape = CIRCLE; } ! else { ! PLAYER_ERROR1("unknown robot shape \"%s\"", shapestring); ! return; } ! } ! MapCspace::~MapCspace() ! { } + // convolve the map with a circular robot to produce the cspace int ! MapCspace::Transform() { unsigned int i,j; *************** *** 375,403 **** char state; ! // a parallel map, telling which cells have already been updated ! unsigned char* updated; ! printf("MapCspace creating C-space for circular robot with radius %.3fm...", this->robot_radius); fflush(NULL); - assert(updated = (unsigned char*)calloc(this->size_x * this->size_y, - sizeof(unsigned char))); - // compute robot radius in map cells ! r = (int)rint(this->robot_radius / this->resolution); ! for(j=0; j < this->size_y; j++) { ! for(i=0; i < this->size_x; i++) { ! // don't double-update ! if(updated[MAP_IDX(this,i,j)]) ! continue; ! ! state = this->mapdata[MAP_IDX(this,i,j)]; // grow both occupied and unknown regions ! if(state >= 0) { for(dj = -r; dj <= r; dj++) --- 175,199 ---- char state; ! // allocate the transformed map ! new_map = source_map; ! new_data = new char[new_map.width * new_map.height]; ! memcpy(new_data,source_data,new_map.width * new_map.height); ! PLAYER_MSG1(5,"MapCspace creating C-space for circular robot with radius %.3fm:", this->robot_radius); fflush(NULL); // compute robot radius in map cells ! r = (int)rint(this->robot_radius / source_map.scale); ! PLAYER_MSG1(5,"Robot Radius in map Cells: %d",r); ! for(j=0; j < this->source_map.height; j++) { ! for(i=0; i < this->source_map.width; i++) { ! state = this->source_data[MAP_IDX(source_map,i,j)]; // grow both occupied and unknown regions ! if(state <= 0) { for(dj = -r; dj <= r; dj++) *************** *** 410,421 **** // make sure we stay on the map ! if(!MAP_VALID(this,i+di,j+dj)) continue; // don't change occupied to uknown ! if(this->mapdata[MAP_IDX(this,i+di,j+dj)] < state) { ! this->mapdata[MAP_IDX(this,i+di,j+dj)] = state; ! updated[MAP_IDX(this,i+di,j+dj)] = 1; } } --- 206,216 ---- // make sure we stay on the map ! if(!MAP_VALID(new_map,i+di,j+dj)) continue; // don't change occupied to uknown ! if(this->new_data[MAP_IDX(new_map,i+di,j+dj)] > state) { ! this->new_data[MAP_IDX(new_map,i+di,j+dj)] = state; } } *************** *** 424,668 **** } } - - free(updated); - - puts("Done."); - - return(0); - } - - int - MapCspace::Shutdown() - { - free(this->mapdata); - return(0); - } - - - //////////////////////////////////////////////////////////////////////////////// - // Process an incoming message - int MapCspace::ProcessMessage(ClientData * client, player_msghdr * hdr, uint8_t * data, uint8_t * resp_data, size_t * resp_len) - { - assert(hdr); - assert(data); - assert(resp_data); - assert(resp_len); - - - if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_MAP_GET_INFO, device_id)) - { - assert(*resp_len > sizeof(player_map_info_t)); - *resp_len = sizeof(player_map_info_t); - player_map_info_t & info = *reinterpret_cast<player_map_info_t *> (resp_data); - - info.scale = htonl((uint32_t)rint(1e3 / this->resolution)); - - info.width = htonl((uint32_t) (this->size_x)); - info.height = htonl((uint32_t) (this->size_y)); - - return PLAYER_MSGTYPE_RESP_ACK; - } - - if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_MAP_GET_DATA, device_id)) - { - player_map_data_t & map_data = *reinterpret_cast<player_map_data_t *> (resp_data); - - unsigned int i, j; - unsigned int oi, oj, si, sj; - - // Construct reply - memcpy(resp_data, data, hdr->size); - - oi = ntohl(map_data.col); - oj = ntohl(map_data.row); - si = ntohl(map_data.width); - sj = ntohl(map_data.height); - - // Grab the pixels from the map - for(j = 0; j < sj; j++) - { - for(i = 0; i < si; i++) - { - if((i * j) <= PLAYER_MAP_MAX_CELLS_PER_TILE) - { - if(MAP_VALID(this, i + oi, j + oj)) - map_data.data[i + j * si] = this->mapdata[MAP_IDX(this, i+oi, j+oj)]; - else - { - PLAYER_WARN2("requested cell (%d,%d) is offmap", i+oi, j+oj); - map_data.data[i + j * si] = 0; - } - } - else - { - PLAYER_WARN("requested tile is too large; truncating"); - if(i == 0) - { - map_data.width = htonl(si-1); - map_data.height = htonl(j-1); - } - else - { - map_data.width = htonl(i); - map_data.height = htonl(j); - } - } - } - } - - size_t size=sizeof(map_data) - sizeof(map_data.data) + ntohl(map_data.width) * ntohl(map_data.height); - assert(*resp_len >= size); - *resp_len = size; - return PLAYER_MSGTYPE_RESP_ACK; - } - - return -1; - } - - - // Process configuration requests - /*int - MapCspace::PutConfig(player_device_id_t id, void *client, - void* src, size_t len, - struct timeval* timestamp) - { - // Discard bogus empty packets - if(len < 1) - { - PLAYER_WARN("got zero length configuration request; ignoring"); - if(PutReply(client, PLAYER_MSGTYPE_RESP_NACK,NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - return(0); - } - - // Process some of the requests immediately - switch(((unsigned char*) src)[0]) - { - case PLAYER_MAP_GET_INFO_REQ: - HandleGetMapInfo(client, src, len); - break; - case PLAYER_MAP_GET_DATA_REQ: - HandleGetMapData(client, src, len); - break; - default: - PLAYER_ERROR("got unknown config request; ignoring"); - if(PutReply(client, PLAYER_MSGTYPE_RESP_NACK,NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - break; - } - return(0); } - // Handle map info request - void - MapCspace::HandleGetMapInfo(void *client, void *request, int len) - { - int reqlen; - player_map_info_t info; - - // Expected length of request - reqlen = sizeof(info.subtype); - - // check if the config request is valid - if(len != reqlen) - { - PLAYER_ERROR2("config request len is invalid (%d != %d)", len, reqlen); - if (PutReply(client, PLAYER_MSGTYPE_RESP_NACK,NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - return; - } - - if(this->mapdata == NULL) - { - PLAYER_ERROR("NULL map data"); - if(PutReply(client, PLAYER_MSGTYPE_RESP_NACK,NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - return; - } - - // copy in subtype - info.subtype = ((player_map_info_t*)request)->subtype; - - // convert to pixels / kilometer - info.scale = htonl((uint32_t)rint(1e3 / this->resolution)); - - info.width = htonl((uint32_t) (this->size_x)); - info.height = htonl((uint32_t) (this->size_y)); - - // Send map info to the client - if (PutReply(client, PLAYER_MSGTYPE_RESP_ACK, &info, sizeof(info),NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - - return; - } - - // Handle map data request - void - MapCspace::HandleGetMapData(void *client, void *request, int len) - { - int i, j; - int oi, oj, si, sj; - int reqlen; - player_map_data_t data; - - // Expected length of request - reqlen = sizeof(data) - sizeof(data.data); - - // check if the config request is valid - if(len != reqlen) - { - PLAYER_ERROR2("config request len is invalid (%d != %d)", len, reqlen); - if(PutReply(client, PLAYER_MSGTYPE_RESP_NACK,NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - return; - } - - // Construct reply - memcpy(&data, request, len); - - oi = ntohl(data.col); - oj = ntohl(data.row); - si = ntohl(data.width); - sj = ntohl(data.height); - - // Grab the pixels from the map - for(j = 0; j < sj; j++) - { - for(i = 0; i < si; i++) - { - if((i * j) <= PLAYER_MAP_MAX_CELLS_PER_TILE) - { - if(MAP_VALID(this, i + oi, j + oj)) - data.data[i + j * si] = this->mapdata[MAP_IDX(this, i+oi, j+oj)]; - else - { - PLAYER_WARN2("requested cell (%d,%d) is offmap", i+oi, j+oj); - data.data[i + j * si] = 0; - } - } - else - { - PLAYER_WARN("requested tile is too large; truncating"); - if(i == 0) - { - data.width = htonl(si-1); - data.height = htonl(j-1); - } - else - { - data.width = htonl(i); - data.height = htonl(j); - } - } - } - } - - // Send map info to the client - if(PutReply(client, PLAYER_MSGTYPE_RESP_ACK, &data, - sizeof(data) - sizeof(data.data) + - ntohl(data.width) * ntohl(data.height),NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - return; - } - */ --- 219,223 ---- --- NEW FILE: maptransform.cc --- /* * Player - One Hell of a Robot Server * Copyright (C) 2004 Brian Gerkey ge...@st... * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* * $Id: maptransform.cc,v 1.1.2.2 2006/04/19 21:29:28 gerkey Exp $ * * Base class for map transform drivers, simply reimplement the transform method * with your trasformation function. See MapScale for example */ #include "maptransform.h" // this one has no data or commands, just configs MapTransform::MapTransform(ConfigFile* cf, int section) : Driver(cf, section, true, PLAYER_MSGQUEUE_DEFAULT_MAXLEN, PLAYER_MAP_CODE) { PLAYER_MSG0(9,"Initialising the MapTransform Driver"); memset(&source_map,0,sizeof(source_map)); memset(&new_map,0,sizeof(new_map)); // Find our source map if(cf->ReadDeviceAddr(&source_map_addr, section, "requires", PLAYER_MAP_CODE, -1,NULL) != 0) { PLAYER_ERROR("must specify source map"); return; } this->source_data = this->new_data = NULL; } MapTransform::~MapTransform() { } int MapTransform::Setup() { if(this->GetMap() < 0) return(-1); if(this->Transform() < 0) return(-1); delete [] source_data; source_data = NULL; return(0); } // get the map from the underlying map device // TODO: should Unsubscribe from the map on error returns in the function int MapTransform::GetMap() { Device* mapdev; // Subscribe to the map device if(!(mapdev = deviceTable->GetDevice(this->source_map_addr))) { PLAYER_ERROR("unable to locate suitable map device"); return -1; } if(mapdev->Subscribe(this->InQueue) != 0) { PLAYER_ERROR("unable to subscribe to map device"); return -1; } // first, get the map info Message* msg; if(!(msg = mapdev->Request(this->InQueue, PLAYER_MSGTYPE_REQ, PLAYER_MAP_REQ_GET_INFO, NULL, 0, NULL, false))) { PLAYER_ERROR("failed to get map info"); return(-1); } // copy in the map info source_map = *(player_map_info_t*)msg->GetPayload(); delete msg; // allocate space for map cells this->source_data = new char[this->source_map.width * this->source_map.height]; assert(this->source_data); if(!(msg = mapdev->Request(this->InQueue, PLAYER_MSGTYPE_REQ, PLAYER_MAP_REQ_GET_INFO, NULL, 0, NULL, false))) { PLAYER_ERROR("failed to get map info"); return(-1); } // now, get the map data player_map_data_t* data_req; size_t reqlen; unsigned int i,j; unsigned int oi,oj; unsigned int sx,sy; unsigned int si,sj; reqlen = sizeof(player_map_data_t) - PLAYER_MAP_MAX_TILE_SIZE + 4; data_req = (player_map_data_t*)calloc(1, reqlen); assert(data_req); // Tile size sy = sx = (int)sqrt(PLAYER_MAP_MAX_TILE_SIZE); assert(sx * sy < (int)PLAYER_MAP_MAX_TILE_SIZE); oi=oj=0; while((oi < this->source_map.width) && (oj < this->source_map.height)) { si = MIN(sx, this->source_map.width - oi); sj = MIN(sy, this->source_map.height - oj); data_req->col = oi; data_req->row = oj; data_req->width = si; data_req->height = sj; data_req->data_count = 0; if(!(msg = mapdev->Request(this->InQueue, PLAYER_MSGTYPE_REQ, PLAYER_MAP_REQ_GET_DATA, (void*)data_req,reqlen,NULL,false))) { PLAYER_ERROR("failed to get map info"); free(data_req); delete [] source_data; source_data=NULL; return(-1); } player_map_data_t* mapcells = (player_map_data_t*)msg->GetPayload(); // copy the map data for(j=0;j<sj;j++) { for(i=0;i<si;i++) { source_data[MAP_IDX(source_map,oi+i,oj+j)] = mapcells->data[j*si + i]; // mapdata[MAP_IDX(source_map,oi+i,oj+j)].occ_dist = 0; } } delete msg; oi += si; if(oi >= this->source_map.width) { oi = 0; oj += sj; } } free(data_req); // we're done with the map device now if(mapdev->Unsubscribe(this->InQueue) != 0) PLAYER_WARN("unable to unsubscribe from map device"); puts("Done."); PLAYER_MSG3(4,"MapScale read a %d X %d map, at %.3f m/pix\n", this->source_map.width, this->source_map.height, this->source_map.scale); return(0); } int MapTransform::Shutdown() { delete [] this->new_data; new_data = NULL; return(0); } //////////////////////////////////////////////////////////////////////////////// // Process an incoming message int MapTransform::ProcessMessage(MessageQueue * resp_queue, player_msghdr * hdr, void * data) { PLAYER_MSG0(9,"ProcessMessage called for MapTransform Driver"); assert(hdr); assert(data); if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_MAP_REQ_GET_INFO, device_addr)) { PLAYER_MSG0(9,"ProcessMessage called for MapTransform Driver: PLAYER_MAP_REQ_GET_INFO"); Publish(device_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_MAP_REQ_GET_INFO, &new_map, sizeof(new_map), NULL); return 0; } if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_MAP_REQ_GET_DATA, device_addr)) { PLAYER_MSG0(9,"ProcessMessage called for MapTransform Driver: PLAYER_MAP_REQ_GET_DATA"); assert(new_data); player_map_data_t & map_data = *reinterpret_cast<player_map_data_t *> (data); unsigned int i, j; unsigned int oi, oj, si, sj; // Construct reply oi = map_data.col; oj = map_data.row; si = map_data.width; sj = map_data.height; PLAYER_MSG4(9,"Block Requested is: %d,%d + %d,%d",oi,oj,si,sj); // Grab the pixels from the map for(j = 0; j < sj; j++) { for(i = 0; i < si; i++) { if((i * j) <= PLAYER_MAP_MAX_TILE_SIZE) { if(MAP_VALID(new_map, i + oi, j + oj)) map_data.data[i + j * si] = this->new_data[MAP_IDX(new_map, i+oi, j+oj)]; else { PLAYER_WARN2("requested cell (%d,%d) is offmap", i+oi, j+oj); map_data.data[i + j * si] = 0; } } else { PLAYER_WARN("requested tile is too large; truncating"); if(i == 0) { map_data.width = (si-1); map_data.height = (j-1); } else { map_data.width = (i); map_data.height = (j); } } } } map_data.data_count = map_data.width * map_data.height; Publish(device_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, PLAYER_MAP_REQ_GET_DATA, &map_data, sizeof(map_data),NULL); return 0; } return -1; } --- NEW FILE: maptransform.h --- /* * Player - One Hell of a Robot Server * Copyright (C) 2004 Brian Gerkey ge...@st... * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* * $Id: maptransform.h,v 1.1.2.2 2006/04/19 21:29:28 gerkey Exp $ * * Base class for map transform drivers, simply reimplement the transform method * with your trasformation function. See MapScale for example */ #ifndef _MAPTRANSFORM_H_ #define _MAPTRANSFORM_H_ #include <sys/types.h> // required by Darwin #include <netinet/in.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <playercore.h> // compute linear index for given map coords #define MAP_IDX(mf, i, j) ((mf.width) * (j) + (i)) // check that given coords are valid (i.e., on the map) #define MAP_VALID(mf, i, j) ((i >= 0) && (i < mf.width) && (j >= 0) && (j < mf.width)) class MapTransform : public Driver { protected: player_map_info_t source_map; player_devaddr_t source_map_addr; char* source_data; player_map_info_t new_map; char* new_data; // get the map from the underlying map device int GetMap(); // interpolate the map virtual int Transform() = 0; public: MapTransform(ConfigFile* cf, int section); virtual ~MapTransform(); // MessageHandler public: virtual int ProcessMessage(MessageQueue * resp_queue, player_msghdr * hdr, void * data); int Setup(); int Shutdown(); }; #endif Index: mapscale.cc =================================================================== RCS file: /cvsroot/playerstage/code/player/server/drivers/map/mapscale.cc,v retrieving revision 1.11 retrieving revision 1.11.2.1 diff -C2 -d -r1.11 -r1.11.2.1 *** mapscale.cc 23 Feb 2006 18:54:54 -0000 1.11 --- mapscale.cc 19 Apr 2006 21:29:28 -0000 1.11.2.1 *************** *** 87,186 **** ! #include <sys/types.h> // required by Darwin ! #include <netinet/in.h> ! #include <stdlib.h> ! #include <string.h> ! #include <math.h> // use gdk to interpolate #include <gdk-pixbuf/gdk-pixbuf.h> ! #include <player.h> ! #include <drivertable.h> ! #include <devicetable.h> ! #include <error.h> ! ! // compute linear index for given map coords ! #define MAP_IDX(mf, i, j) ((mf->size_x) * (j) + (i)) ! #define NEW_MAP_IDX(mf, i, j) ((mf->new_size_x) * (j) + (i)) ! ! // check that given coords are valid (i.e., on the map) ! #define MAP_VALID(mf, i, j) ((i >= 0) && (i < mf->size_x) && (j >= 0) && (j < mf->size_y)) ! #define NEW_MAP_VALID(mf, i, j) ((i >= 0) && (i < mf->new_size_x) && (j >= 0) && (j < mf->new_size_y)) ! ! extern int global_playerport; ! ! class MapScale : public Driver { private: - double resolution; - unsigned int size_x, size_y; - char* mapdata; - player_device_id_t map_id; - - double new_resolution; - unsigned int new_size_x, new_size_y; - char* new_mapdata; - - // get the map from the underlying map device - int GetMap(); // interpolate the map ! int Scale(); - // Handle map info request - void HandleGetMapInfo(void *client, void *request, int len); - // Handle map data request - void HandleGetMapData(void *client, void *request, int len); - public: ! MapScale(ConfigFile* cf, int section, player_device_id_t id, double new_resolution); ~MapScale(); - int ProcessMessage(ClientData * client, player_msghdr * hdr, uint8_t * data, uint8_t * resp_data, size_t * resp_len); - int Setup(); - int Shutdown(); - /* int PutConfig(player_device_id_t id, void *client, - void* src, size_t len, - struct timeval* timestamp);*/ }; ! Driver* ! MapScale_Init(ConfigFile* cf, int section) { ! player_device_id_t map_id; ! double resolution; ! ! // Must have an input map ! if (cf->ReadDeviceId(&map_id, section, "requires", ! PLAYER_MAP_CODE, -1, NULL) != 0) ! { ! PLAYER_ERROR("must specify input map"); ! return(NULL); ! } ! if((resolution = cf->ReadLength(section,"resolution",-1.0)) < 0) ! { ! PLAYER_ERROR("must specify positive map resolution"); ! return(NULL); ! } ! ! return((Driver*)(new MapScale(cf, section, map_id, resolution))); } ! // a driver registration function ! void ! MapScale_Register(DriverTable* table) { table->AddDriver("mapscale", MapScale_Init); } // this one has no data or commands, just configs ! MapScale::MapScale(ConfigFile* cf, int section, player_device_id_t id, double res) ! : Driver(cf, section, true, PLAYER_MSGQUEUE_DEFAULT_MAXLEN, PLAYER_MAP_CODE, PLAYER_READ_MODE) { ! this->mapdata = this->new_mapdata = NULL; ! this->size_x = this->size_y = 0; ! this->new_size_x = this->new_size_y = 0; ! this->map_id = id; ! this->new_resolution = res; } --- 87,133 ---- ! #include "maptransform.h" // use gdk to interpolate #include <gdk-pixbuf/gdk-pixbuf.h> ! class MapScale : public MapTransform { private: // interpolate the map ! int Transform(); public: ! MapScale(ConfigFile* cf, int section); ~MapScale(); }; ! //////////////////////////////////////////////////////////////////////////////// ! // Create an instance of the driver ! Driver* MapScale_Init( ConfigFile* cf, int section) { ! return ((Driver*) (new MapScale(cf, section))); } ! ! //////////////////////////////////////////////////////////////////////////////// ! // Register the driver ! void MapScale_Register(DriverTable* table) { table->AddDriver("mapscale", MapScale_Init); + return; } + // this one has no data or commands, just configs ! MapScale::MapScale(ConfigFile* cf, int section) ! : MapTransform(cf, section) { ! if((new_map.scale = cf->ReadLength(section,"resolution",-1.0)) < 0) ! { ! PLAYER_ERROR("must specify positive map resolution"); ! return; ! } } *************** *** 189,348 **** } - int - MapScale::Setup() - { - if(this->GetMap() < 0) - return(-1); - if(this->Scale() < 0) - return(-1); - - return(0); - } - - // get the map from the underlying map device - // TODO: should Unsubscribe from the map on error returns in the function - int - MapScale::GetMap() - { - Driver* mapdevice; - - // Subscribe to the map device - if(!(mapdevice = SubscribeInternal(map_id))) - { - PLAYER_ERROR("unable to locate suitable map device"); - return(-1); - } - /* if(mapdevice == this) - { - PLAYER_ERROR("tried to subscribe to self; specify a *different* map index"); - return(-1); - } - if(mapdevice->Subscribe(map_id) != 0) - { - PLAYER_ERROR("unable to subscribe to map device"); - return(-1); - }*/ - - printf("MapScale: Loading map from map:%d...\n", this->map_id.index); - fflush(NULL); - - // Fill in the map structure - - // first, get the map info - //int replen; - unsigned short reptype; - player_map_info_t info; - //struct timeval ts; - /* info.subtype = PLAYER_MAP_GET_INFO_REQ; - if((replen = mapdevice->Request(map_id, this, - &info, sizeof(info.subtype), NULL, - &reptype, &info, sizeof(info), &ts)) == 0) - { - PLAYER_ERROR("failed to get map info"); - return(-1); - }*/ - size_t resp_size = sizeof(info); - reptype = mapdevice->ProcessMessage(PLAYER_MSGTYPE_REQ, PLAYER_MAP_GET_INFO, - map_id, 0, (uint8_t *)&info, (uint8_t *)&info, &resp_size); - - if (reptype != PLAYER_MSGTYPE_RESP_ACK) - { - PLAYER_ERROR("failed to get map info"); - return(-1); - } - - // copy in the map info - this->resolution = 1/(ntohl(info.scale) / 1e3); - this->size_x = ntohl(info.width); - this->size_y = ntohl(info.height); - - // allocate space for map cells - assert(this->mapdata = (char*)malloc(sizeof(char) * - this->size_x * - this->size_y)); - - // allocate space for map cells - this->mapdata = (char*)malloc(sizeof(char) * - this->size_x * - this->size_y); - - assert(this->mapdata); - - // now, get the map data - player_map_data_t data_req; - unsigned int reqlen; - unsigned int i,j; - unsigned int oi,oj; - unsigned int sx,sy; - unsigned int si,sj; - - //data_req.subtype = PLAYER_MAP_GET_DATA_REQ; - - // Tile size - sy = sx = (int)sqrt(sizeof(data_req.data)); - assert(sx * sy < (int)sizeof(data_req.data)); - oi=oj=0; - while((oi < this->size_x) && (oj < this->size_y)) - { - si = MIN(sx, this->size_x - oi); - sj = MIN(sy, this->size_y - oj); - - data_req.col = htonl(oi); - data_req.row = htonl(oj); - data_req.width = htonl(si); - data_req.height = htonl(sj); - - reqlen = sizeof(data_req) - sizeof(data_req.data); - resp_size = sizeof(data_req); - reptype = mapdevice->ProcessMessage(PLAYER_MSGTYPE_REQ, PLAYER_MAP_GET_DATA, - map_id, reqlen, (uint8_t *)&data_req, (uint8_t *)&data_req, &resp_size); - - - - /* if((replen = mapdevice->Request(map_id, this, - &data_req, reqlen, NULL, - &reptype, &data_req, - sizeof(data_req), &ts)) == 0)*/ - if (reptype != PLAYER_MSGTYPE_RESP_ACK) - { - PLAYER_ERROR("failed to get map info"); - return(-1); - } - else if(resp_size != (reqlen + si * sj)) - { - PLAYER_ERROR2("got less map data than expected (%d != %d)", - resp_size, reqlen + si*sj); - return(-1); - } - - // copy the map data - for(j=0;j<sj;j++) - { - for(i=0;i<si;i++) - { - this->mapdata[MAP_IDX(this,oi+i,oj+j)] = data_req.data[j*si + i]; - } - } - - oi += si; - if(oi >= this->size_x) - { - oi = 0; - oj += sj; - } - } - - // we're done with the map device now - UnsubscribeInternal(map_id); - - puts("Done."); - printf("MapScale read a %d X %d map, at %.3f m/pix\n", - this->size_x, this->size_y, this->resolution); - return(0); - } - // interpolate the map int ! MapScale::Scale() { unsigned int i,j; --- 136,142 ---- } // interpolate the map int ! MapScale::Transform() { unsigned int i,j; *************** *** 359,385 **** int new_rowstride; - printf("MapScale scaling to resolution %.3fm...", - this->new_resolution); - fflush(NULL); - has_alpha = FALSE; bits_per_sample = 8; n_channels = 3; ! rowstride = size_x * sizeof(guchar) * n_channels; ! assert(map_pixels = (guchar*)calloc(this->size_x * this->size_y, ! sizeof(guchar)*n_channels)); // fill in the image from the map ! for(j=0; j<this->size_y; j++) { ! for(i=0; i<this->size_x; i++) { // fill the corresponding image pixel ! p = map_pixels + (this->size_y - j - 1)*rowstride + i*n_channels; ! if(this->mapdata[MAP_IDX(this,i,j)] == -1) *p = 255; ! else if(this->mapdata[MAP_IDX(this,i,j)] == 0) *p = 127; else --- 153,176 ---- int new_rowstride; has_alpha = FALSE; bits_per_sample = 8; n_channels = 3; ! rowstride = source_map.width * sizeof(guchar) * n_channels; ! map_pixels = (guchar*)calloc(this->source_map.width * this->source_map.height, ! sizeof(guchar)*n_channels); ! assert(map_pixels); // fill in the image from the map ! for(j=0; j<this->source_map.height; j++) { ! for(i=0; i<this->source_map.width; i++) { // fill the corresponding image pixel ! p = map_pixels + (this->source_map.height - j - 1)*rowstride + i*n_channels; ! if(this->source_data[MAP_IDX(source_map,i,j)] == -1) *p = 255; ! else if(this->source_data[MAP_IDX(source_map,i,j)] == 0) *p = 127; else *************** *** 392,427 **** has_alpha, bits_per_sample, ! this->size_x, ! this->size_y, rowstride, NULL,NULL))); ! scale_factor = this->resolution / this->new_resolution; ! this->new_size_x = (int)rint(this->size_x * scale_factor); ! this->new_size_y = (int)rint(this->size_y * scale_factor); ! g_assert((new_pixbuf = gdk_pixbuf_scale_simple(pixbuf, ! this->new_size_x, ! this->new_size_y, ! GDK_INTERP_HYPER))); new_map_pixels = gdk_pixbuf_get_pixels(new_pixbuf); new_rowstride = gdk_pixbuf_get_rowstride(new_pixbuf); ! assert(this->new_mapdata = (char*)calloc(this->new_size_x * this->new_size_y, ! sizeof(char))); // fill in the map from the scaled image ! for(j=0; j<this->new_size_y; j++) { ! for(i=0; i<this->new_size_x; i++) { // fill the corresponding map cell ! p = new_map_pixels + (this->new_size_y-j-1)*new_rowstride + i*n_channels; ! if(*p > 0.9 * 255) ! this->new_mapdata[NEW_MAP_IDX(this,i,j)] = -1; ! else if(*p < 0.1 * 255) ! this->new_mapdata[NEW_MAP_IDX(this,i,j)] = 1; else ! this->new_mapdata[NEW_MAP_IDX(this,i,j)] = 0; } } --- 183,223 ---- has_alpha, bits_per_sample, ! this->source_map.width, ! this->source_map.height, rowstride, NULL,NULL))); ! scale_factor = this->source_map.scale / this->new_map.scale; ! this->new_map.width = static_cast<unsigned int> (rint(this->source_map.width * scale_factor)); ! this->new_map.height = static_cast<unsigned int> (rint(this->source_map.height * scale_factor)); ! ! PLAYER_MSG3(4,"MapScale: New map is %dx%d scale %f",new_map.width,new_map.height,new_map.scale); ! new_pixbuf = gdk_pixbuf_scale_simple(pixbuf, ! this->new_map.width, ! this->new_map.height, ! GDK_INTERP_HYPER); ! g_assert(new_pixbuf); ! new_map_pixels = gdk_pixbuf_get_pixels(new_pixbuf); new_rowstride = gdk_pixbuf_get_rowstride(new_pixbuf); ! this->new_data = new char[this->new_map.width * this->new_map.height]; ! assert(new_data); // fill in the map from the scaled image ! for(j=0; j<this->new_map.height; j++) { ! for(i=0; i<this->new_map.width; i++) { // fill the corresponding map cell ! p = new_map_pixels + (this->new_map.height-j-1)*new_rowstride + i*n_channels; ! if(*p > 0.66 * 255) ! this->new_data[MAP_IDX(new_map,i,j)] = -1; ! else if(*p < 0.33 * 255) ! this->new_data[MAP_IDX(new_map,i,j)] = 1; else ! this->new_data[MAP_IDX(new_map,i,j)] = 0; ! // printf("%d %d %d %d \n",i,j,*p, this->new_mapdata[MAP_IDX(scaled_map,i,j)]); } } *************** *** 432,675 **** // automatically. free(map_pixels); g_object_unref((GObject*)new_pixbuf); - free(this->mapdata); - - printf("Done. New map is %d X %d.\n", this->new_size_x, this->new_size_y); - - return(0); - } - - int - MapScale::Shutdown() - { - free(this->new_mapdata); - return(0); - } - - //////////////////////////////////////////////////////////////////////////////// - // Process an incoming message - int MapScale::ProcessMessage(ClientData * client, player_msghdr * hdr, uint8_t * data, uint8_t * resp_data, size_t * resp_len) - { - assert(hdr); - assert(data); - assert(resp_data); - assert(resp_len); - - - if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_MAP_GET_INFO, device_id)) - { - assert(*resp_len > sizeof(player_map_info_t)); - *resp_len = sizeof(player_map_info_t); - player_map_info_t & info = *reinterpret_cast<player_map_info_t *> (resp_data); - - info.scale = htonl((uint32_t)rint(1e3 / this->resolution)); - - info.width = htonl((uint32_t) (this->size_x)); - info.height = htonl((uint32_t) (this->size_y)); - - return PLAYER_MSGTYPE_RESP_ACK; - } - - if (MatchMessage(hdr, PLAYER_MSGTYPE_REQ, PLAYER_MAP_GET_DATA, device_id)) - { - player_map_data_t & map_data = *reinterpret_cast<player_map_data_t *> (resp_data); - - unsigned int i, j; - unsigned int oi, oj, si, sj; - - // Construct reply - memcpy(resp_data, data, hdr->size); - - oi = ntohl(map_data.col); - oj = ntohl(map_data.row); - si = ntohl(map_data.width); - sj = ntohl(map_data.height); - - // Grab the pixels from the map - for(j = 0; j < sj; j++) - { - for(i = 0; i < si; i++) - { - if((i * j) <= PLAYER_MAP_MAX_CELLS_PER_TILE) - { - if(MAP_VALID(this, i + oi, j + oj)) - map_data.data[i + j * si] = this->mapdata[MAP_IDX(this, i+oi, j+oj)]; - else - { - PLAYER_WARN2("requested cell (%d,%d) is offmap", i+oi, j+oj); - map_data.data[i + j * si] = 0; - } - } - else - { - PLAYER_WARN("requested tile is too large; truncating"); - if(i == 0) - { - map_data.width = htonl(si-1); - map_data.height = htonl(j-1); - } - else - { - map_data.width = htonl(i); - map_data.height = htonl(j); - } - } - } - } - - size_t size=sizeof(map_data) - sizeof(map_data.data) + ntohl(map_data.width) * ntohl(map_data.height); - assert(*resp_len >= size); - *resp_len = size; - return PLAYER_MSGTYPE_RESP_ACK; - } - - return -1; - } - - // Process configuration requests - /*int - MapScale::PutConfig(player_device_id_t id, void *client, - void* src, size_t len, - struct timeval* timestamp) - { - // Discard bogus empty packets - if(len < 1) - { - PLAYER_WARN("got zero length configuration request; ignoring"); - if(PutReply(client, PLAYER_MSGTYPE_RESP_NACK,NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - return(0); - } - - // Process some of the requests immediately - switch(((unsigned char*) src)[0]) - { - case PLAYER_MAP_GET_INFO_REQ: - HandleGetMapInfo(client, src, len); - break; - case PLAYER_MAP_GET_DATA_REQ: - HandleGetMapData(client, src, len); - break; - default: - PLAYER_ERROR("got unknown config request; ignoring"); - if(PutReply(client, PLAYER_MSGTYPE_RESP_NACK,NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - break; - } return(0); } - // Handle map info request - void - MapScale::HandleGetMapInfo(void *client, void *request, int len) - { - int reqlen; - player_map_info_t info; - - // Expected length of request - reqlen = sizeof(info.subtype); - - // check if the config request is valid - if(len != reqlen) - { - PLAYER_ERROR2("config request len is invalid (%d != %d)", len, reqlen); - if (PutReply(client, PLAYER_MSGTYPE_RESP_NACK,NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - return; - } - - if(this->new_mapdata == NULL) - { - PLAYER_ERROR("NULL map data"); - if(PutReply(client, PLAYER_MSGTYPE_RESP_NACK,NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - return; - } - - // copy in subtype - info.subtype = ((player_map_info_t*)request)->subtype; - - // convert to pixels / kilometer - info.scale = htonl((uint32_t)rint(1e3 / this->new_resolution)); - - info.width = htonl((uint32_t) (this->new_size_x)); - info.height = htonl((uint32_t) (this->new_size_y)); - - // Send map info to the client - if (PutReply(client, PLAYER_MSGTYPE_RESP_ACK, &info, sizeof(info),NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - - return; - } - - // Handle map data request - void - MapScale::HandleGetMapData(void *client, void *request, int len) - { - int i, j; - int oi, oj, si, sj; - int reqlen; - player_map_data_t data; - - // Expected length of request - reqlen = sizeof(data) - sizeof(data.data); - - // check if the config request is valid - if(len != reqlen) - { - PLAYER_ERROR2("config request len is invalid (%d != %d)", len, reqlen); - if(PutReply(client, PLAYER_MSGTYPE_RESP_NACK,NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - return; - } - - // Construct reply - memcpy(&data, request, len); - - oi = ntohl(data.col); - oj = ntohl(data.row); - si = ntohl(data.width); - sj = ntohl(data.height); - - // Grab the pixels from the map - for(j = 0; j < sj; j++) - { - for(i = 0; i < si; i++) - { - if((i * j) <= PLAYER_MAP_MAX_CELLS_PER_TILE) - { - if(NEW_MAP_VALID(this, i + oi, j + oj)) - data.data[i + j * si] = - this->new_mapdata[NEW_MAP_IDX(this, i+oi, j+oj)]; - else - { - PLAYER_WARN2("requested cell (%d,%d) is offmap", i+oi, j+oj); - data.data[i + j * si] = 0; - } - } - else - { - PLAYER_WARN("requested tile is too large; truncating"); - if(i == 0) - { - data.width = htonl(si-1); - data.height = htonl(j-1); - } - else - { - data.width = htonl(i); - data.height = htonl(j); - } - } - } - } - - // Send map info to the client - if(PutReply(client, PLAYER_MSGTYPE_RESP_ACK, &data, - sizeof(data) - sizeof(data.data) + - ntohl(data.width) * ntohl(data.height),NULL) != 0) - PLAYER_ERROR("PutReply() failed"); - return; - } - */ --- 228,235 ---- // automatically. free(map_pixels); + map_pixels = NULL; g_object_unref((GObject*)new_pixbuf); return(0); } |