// return is only good thru end of level. // using fgetc() since it auto-converts CRLF pairs char *ReadTextFile(char *filename) { FILE *fp; char *filestring = NULL; long int i = 0; struct stat mstat; if (stat(filename, &mstat) != 0) return NULL; while (true) { fp = fopen(filename, "rb"); if (!fp) break; i = ReadFromFile(fp, NULL); filestring = V_Malloc(i, TAG_LEVEL); if (!filestring) break; fseek(fp, 0, SEEK_SET); ReadFromFile(fp, filestring); break; } if (fp) fclose(fp); return(filestring); // return new text }
//========================================= // Push Node to front of the linked list //========================================= void Push(node_t *Node) { stack_t *STK; STK=(stack_t *)V_Malloc(sizeof(stack_t), TAG_LEVEL); STK->StackPtr=Stack; // NULL at start STK->NodePtr=Node; // Tie the Node Stack=STK; // Set to start of Stack }
/* ==================== IMG_compileGLImage() ==================== */ int IMG_compileGLImage (image_t *img) { int i, j, rgba_sz; byte *compiled; if ( img->bpp != 1 && img->bpp != 3 && img->bpp != 4 ) { //Com_Error ( ERR_FATAL, "only handling 24 or 32-bit right now"); Com_Printf( "%s", "only handling 8, 24 or 32-bit right now" ); return -1; } if ( img->bpp == 1 ) { rgba_sz = img->numbytes; } else if ( img->bpp == 3 ) { rgba_sz = img->numbytes * 4; rgba_sz /= 3; } else { rgba_sz = img->numbytes; } rgba_sz += 16; // pad compiled = (byte *) V_Malloc ( rgba_sz ); memset (compiled, 0, rgba_sz); if ( img->bpp == 1 ) { for ( i = 0; i < (int)img->numbytes; i++ ) { compiled[ i ] = img->data[ i ]; } } else if (img->bpp == 3) { for (i = 0, j = 0; i < (int)img->numbytes; i += img->bpp, j+=4) { if (img->data[i] || img->data[i+1] || img->data[i+2]) { compiled[j+2] = img->data[i+0]; compiled[j+1] = img->data[i+1]; compiled[j+0] = img->data[i+2]; compiled[j+3] = 255; } } } else { for (i = 0, j = 0; i < (int)img->numbytes; i += img->bpp, j+=4) { compiled[j+2] = img->data[i+0]; compiled[j+1] = img->data[i+1]; compiled[j+0] = img->data[i+2]; compiled[j+3] = img->data[i+3]; } } img->compiled = compiled; return 0; }
image_t * IMG_readfileTGA (const char *fullpath, image_t *img) { //FILE *fp; byte tga_header_buf[18]; int sz; // int i,j; filehandle_t fh; if ( ! FS_FOpenReadOnly( fullpath, &fh ) ) Com_Error ( ERR_FATAL, "couldn't open file: %s\n", fullpath); if ( ! FS_Read( (void *)tga_header_buf, 18, fh ) ) Com_Error ( ERR_FATAL, "couldn't read file: %s\n", fullpath); IMG_copyHeaderTGA (&img->header.tga, tga_header_buf); sz = FS_GetFileSize( fh ); if ( sz < 0 ) Com_Error( ERR_FATAL, "returned bad size, file not found?\n" ); img->data = (byte *)V_Malloc( sz - 18 ); img->numbytes = FS_ReadAll( img->data, fh ); if ( !img->numbytes ) Com_Error ( ERR_FATAL, "error reading rest of file: %s\n", fullpath); if ( img->numbytes != sz-18 ) Com_Error ( ERR_WARNING, "sizes don't match %i %i\n", img->numbytes, sz ); img->type = IMG_TGA; img->h = img->header.tga.height; img->w = img->header.tga.width; img->bpp = img->header.tga.pixel_size / 8; FS_FClose( fh ); return img; }
//========================================= int FindPath(vec3_t start, vec3_t destination) { node_t *StartNode; node_t *BestNode; node_t *tNode; int NodeNumD; int NodeNumS; int g,c,i; float h; vec3_t tstart,tdest; VectorCopy(start,tstart); VectorCopy(destination,tdest); // Get NodeNum of start vector NodeNumS=GetNodeNum(tstart); if (NodeNumS==-1) { //gi.dprintf("bad nodenum at start\n"); return 0; // ERROR } // Get NodeNum of destination vector NodeNumD=GetNodeNum(tdest); if (NodeNumD==-1) { // gi.dprintf("bad nondenum at end\n"); return 0; // ERROR } // Allocate OPEN/CLOSED list pointers.. OPEN=(node_t *)V_Malloc(sizeof(node_t), TAG_LEVEL); // OPEN=(node_t *)malloc(sizeof(node_t)); OPEN->NextNode=NULL; CLOSED=(node_t *)V_Malloc(sizeof(node_t), TAG_LEVEL); //CLOSED=(node_t *)malloc(sizeof(node_t)); CLOSED->NextNode=NULL; //================================================ // This is our very first NODE! Our start vector //================================================ StartNode=(node_t *)V_Malloc(sizeof(node_t), TAG_LEVEL); //StartNode=(node_t *)malloc(sizeof(node_t)); StartNode->nodenum=NodeNumS; // starting position nodenum StartNode->g=g=0; // we haven't gone anywhere yet StartNode->h=h=distance(start, destination);//fabs(vDiff(start,destination)); // calculate remaining distance (heuristic estimate) GHz - changed to fabs() StartNode->f=g+h; // total cost from start to finish for (c=0;c < NUMCHILDS;c++) StartNode->Child[c]=NULL; // no children for search pattern yet StartNode->NextNode=NULL; StartNode->PrevNode=NULL; //================================================ // next node in open list points to our starting node OPEN->NextNode=BestNode=StartNode; // First node on OPEN list.. //GHz - need to free these nodes too! //NodeList[NodeCount++] = OPEN; // NodeList[NodeCount++] = CLOSED; NodeCount+=2; for (;;) { tNode=BestNode; // Save last valid node BestNode=(node_t *)NextBestNode(NodeNumS, NodeNumD); // Get next node from OPEN list if (!BestNode) { //gi.dprintf("ran out of nodes to search\n"); return 0;//GHz // BestNode=tNode; // Last valid node.. // break; } if (BestNode->nodenum==NodeNumD) break;// we there yet? ComputeSuccessors(BestNode,NodeNumD);} // Search from here.. //================================================ RemoveDuplicates(BestNode, CLOSED);//FIXME: move this up before the start==end crash check // gi.dprintf("%d: processed %d nodes\n", level.framenum,NodeCount); if (BestNode==StartNode) { // Start==End?? FreeStack(StartNode);//FIXME: may cause crash //gi.dprintf("start==end\n"); return 0; } //gi.dprintf("Start = %d End = %d\n", NodeNumS, NodeNumD); // gi.dprintf("Printing tNode (in reverse):\n"); // PrintNodes(BestNode, true); // gi.dprintf("Printing OPEN list:\n"); //PrintNodes(OPEN, false); //gi.dprintf("Printing CLOSED list:\n"); // PrintNodes(CLOSED, false); BestNode->NextNode=NULL; // Must tie this off! // How many nodes we got? tNode=BestNode; i=0; while (tNode) { i++; // How many nodes? tNode=tNode->PrevNode; } if (i <= 2) { // Only nodes are Start and End?? FreeStack(BestNode);//FIXME: may cause crash //gi.dprintf("only start and end nodes\n"); return 0; } // Let's allocate our own stuff... //CLOSED->NextNode = NULL;//GHz - only needs to be null if we are using freestack() numpts=i; //GHz - free old memory //V_Free(Waypoint); Waypoint=(int *)V_Malloc(numpts*sizeof(int), TAG_LEVEL); //Waypoint=(int *)malloc(numpts*sizeof(int)); // Now, we have to assign the nodenum's along // this path in reverse order because that is // the way the A* algorithm finishes its search. // The last best node it visited was the END! // So, we copy them over in reverse.. No biggy.. tNode=BestNode; while (BestNode) { Waypoint[--i]=BestNode->nodenum;//GHz: how/when is this freed? BestNode=BestNode->PrevNode; } // NOTE: At this point, if our numpts returned is not // zero, then a path has been found! To follow this // path we simply follow node[Waypoint[i]].origin // because Waypoint array is filled with indexes into // our node[i] array of valid vectors in the map.. // We did it!! Now free the stack and exit.. //================================================ //++++++++++ GHz NOTES +++++++++++++ // FreeStack() is flawed because the lists have nodes that point to nodes on other lists // so if you free one list, then the next list will crash when it encounters a node with // an invalid pointer (node was freed in last list) //++++++++++++++++++++++++++++++++++ FreeStack(tNode); // Release ALL resources!! //GHz: cleanup test/debugging //for (i=0;i<NodeCount;i++) //{ // V_Free(NodeList[i]); // } // OPEN = NULL; //CLOSED = NULL; NodeCount = 0; //TODO: performance... cpu usage is still very high //TODO: grid editor, save grid to disk //TODO: need some way of handling manually edited grid // because NextNode() only searches within a specific 32x32 pattern // gi.dprintf("%d: found %d\n",level.framenum,numpts); return (numpts); }
//=========================================== // Successor Nodes all pushed onto OPEN list //=========================================== void GetSuccessorNodes(node_t *StartNode, int NodeNumS, int NodeNumD) { node_t *Old,*Successor; node_t *tNode1,*tNode2; int g,c; float h; // NOTE: NodeNumS is the index of a node that was found by the node searching routine //================================ // Has NodeNumS been Searched yet? //================================ // see if this node is already on the OPEN list Old = CheckLIST(OPEN, NodeNumS); if (Old) { // node was found on the OPEN list // this means the node was found before (as a child of another node) // but not yet searched (as a parent node) for (c = 0; c < NUMCHILDS; c++) { // break on the first available child slot of StartNode if (!StartNode->Child[c]) break; } // if we found an empty child slot, use it, otherwise use the last one StartNode->Child[((c < NUMCHILDS)?c:(NUMCHILDS-1))] = Old; // have we gone farther with this node than StartNode? if (StartNode->g + 1 < Old->g) { Old->g = g = StartNode->g + 1; // make node one step beyond StartNode Old->f = g + Old->h; // update total cost Old->PrevNode = StartNode; // reverse link to StartNode } return; } //================================== // Has NodeNumS been searched yet? //================================== Old=CheckLIST(CLOSED,NodeNumS); if (Old!=NULL) { // node has been searched before for (c=0;c < NUMCHILDS;c++) if (StartNode->Child[c]==NULL) break; StartNode->Child[((c < NUMCHILDS)?c:(NUMCHILDS-1))]=Old; if (StartNode->g+1 < Old->g) { Old->g=g=StartNode->g+1; Old->f=g+Old->h; Old->PrevNode=StartNode; PropagateDown(Old); } return; } //======================================= // It is NOT on the OPEN or CLOSED List!! //======================================= // Make Successor a Child of StartNode //======================================= //Successor=(node_t *)malloc(sizeof(node_t)); Successor=(node_t *)V_Malloc(sizeof(node_t), TAG_LEVEL); Successor->nodenum=NodeNumS; Successor->g=g=StartNode->g+1; //GHz - track node memory use so we can free this later // NodeList[NodeCount++] = Successor; NodeCount++; // NOTE: the heuristic estimate of the remaining path from this node // to the destination node is given by the difference between the 2 // vectors. You can come up with your own estimate.. Successor->h=h=distance(pathnode[NodeNumS], pathnode[NodeNumD]);//fabs(vDiff(node[NodeNumS].origin,node[NodeNumD].origin));//GHz - changed to fabs() Successor->f=g+h; Successor->PrevNode=StartNode; // reverse link to StartNode Successor->NextNode=NULL; // make all child links of new Successor node NULL for (c=0;c < NUMCHILDS;c++) Successor->Child[c]=NULL; for (c=0;c < NUMCHILDS;c++) if (StartNode->Child[c]==NULL) break; // Find first empty Child[] of StartNode StartNode->Child[((c < NUMCHILDS)?c:(NUMCHILDS-1))]=Successor; // make Successor a child of StartNode //================================= // Insert Successor into OPEN List //================================= tNode1=OPEN; tNode2=OPEN->NextNode; // find node in OPEN list with f-cost greater than Successor node while (tNode2 && (tNode2->f < Successor->f)) { tNode1=tNode2; tNode2=tNode2->NextNode; } Successor->NextNode=tNode2; tNode1->NextNode=Successor; //gi.dprintf("added node %d to the OPEN list\n", Successor->nodenum); }
image_t *IMG_readfileBMP ( const char *fullpath, image_t *img ) { FILE *fp; int i, bytesread; int datasize; int infosize; byte buf[128]; bmp_header_t *h; bmp_info_t *info; register byte temp; // open if ((fp = fopen(fullpath, "rb")) == NULL) { Com_Printf("cant read %s \n", fullpath); return NULL; } // read header straight in if (fread(buf, 14, 1, fp) == NULL) { Com_Printf("error reading header\n"); return NULL; } h = &img->header.bmp; h->magic = (unsigned short) *(unsigned short *)buf; h->totalBytes = (unsigned int) *(unsigned int *)&buf[2]; h->reserved1 = h->reserved2 = 0; h->dataOffsetBytes = (unsigned int) *(unsigned int *)&buf[10]; // check magic number if (img->header.bmp.magic != 19778) { Com_Printf("Not a Bitmap File\n"); return NULL; } // read info portion of header memset( buf , 0, sizeof(buf) ); //infosize = img->header.bmp.dataOffsetBytes - sizeof(bmp_header_t); infosize = img->header.bmp.dataOffsetBytes - 14; info = (bmp_info_t *) buf; if (fread(info, infosize, 1, fp) == NULL) { Com_Printf("error reading bitmap info from file\n"); return NULL; } // record info if (! IMG_getBmpInfo(img, info) ) { return NULL; } // malloc data portion // 2 bytes padding (0x00, 0x00) on the end of bmp datasize = img->header.bmp.totalBytes - img->header.bmp.dataOffsetBytes; img->data = (byte *) V_Malloc (datasize); memset (img->data, 0, datasize); img->numbytes = datasize; img->type = IMG_BMP; // get data fseek ( fp, img->header.bmp.dataOffsetBytes, SEEK_SET ); /* do { i = fread(img->data, 1, 1024, fp); bytesread += i; if (i <= 0) break; } while(1); */ // read image data bytesread = 0; while ((i = fread(&img->data[bytesread], 1, 8192, fp)) > 0) bytesread += i; if ( bytesread != datasize ) { Com_Printf("bitmap: incorrect datasize: %d\n", bytesread); return NULL; } return img; }
// tex and mask should already be created. we'll re-read in each of their // file's data, and then create another image and GL compile it, storing // all of the new info to ip. Only supports textures that have an equal // width and height value, and that value must be a powerof 2. int IMG_CombineTextureMaskPow2( image_t *tex, image_t *mask, image_t **ipp ) { int i; if ( !( tex && mask && ipp ) ) return -1; if ( tex->h != tex->w || mask->h != mask->w ) return -2; if ( !ISPOWEROF2( tex->h ) ) return -3; // alloc the image image_t *ip = (image_t *) V_Malloc( sizeof(image_t) ); image_t *m_ip = (image_t*) V_Malloc( sizeof(image_t) ); memset( ip, 0, sizeof(image_t) ); memset( m_ip, 0, sizeof(image_t) ); char path[ 512 ]; snprintf( path, 512, "%s\\%s", fs_gamepath->string(), tex->syspath ); // read the TEX file switch ( tex->type ) { case IMG_TGA: IMG_readfileTGA( path, ip ); break; case IMG_BMP: IMG_readfileBMP( path, ip ); break; case IMG_GIF: case IMG_JPG: case IMG_PCX: case IMG_PPM: case IMG_PNG: default: Com_Printf( "image type: %s not supported\n", IMG_Error(tex->type) ); V_Free(ip); V_Free(m_ip); return -6; } // save path info of the texture image ip->name[0] = 0; ip->syspath[0] = 0; strcpy( ip->name, strip_path( &path[0] ) ); strcpy( ip->syspath, strip_gamepath( &path[0] ) ); // read in the MASK file snprintf( path, 512, "%s\\%s", fs_gamepath->string(), mask->syspath ); switch ( mask->type ) { case IMG_TGA: IMG_readfileTGA( path, m_ip ); break; case IMG_BMP: IMG_readfileBMP( path, m_ip ); break; case IMG_GIF: case IMG_JPG: case IMG_PCX: case IMG_PPM: case IMG_PNG: default: Com_Printf( "image type: %s not supported\n", IMG_Error(mask->type) ); if ( ip->data ) V_Free( ip->data ); V_Free(ip); V_Free(m_ip); return -7; } int err_cond = 0; // allocates compiled array & formats data into it if ( IMG_compileGLImage( ip ) ) err_cond = 1; if ( IMG_compileGLImage( m_ip ) ) err_cond = 1; byte *rsmp = NULL; if ( !err_cond ) { int scale = ip->w / m_ip->w; // difference between scales // single channel greyscale mask int r_sz = ip->h * ip->w; // 1 byte for each pixel rsmp = (byte *) V_Malloc( ip->h * ip->w ); memset( rsmp, 0, r_sz ); // convert mask from it's resident format to be the same dimension // as the texture image int h, i, j, k, rsmp_i, rsmp_j, pix; /// foreach Row in Mask // for each row in m_ip ==> j for ( j = 0; j < m_ip->h; j++ ) { /// foreach col in Mask // for each col in m_ip ==> i for ( i = 0; i < m_ip->w; i++ ) { /// extrapolate Mask Pixel to Cover all of it's corresponding pixels /// in the new re-sampled mask // ROWS: ( j * scale ) to ( j * scale + scale ) for ( k = 0; k < scale; k++ ) { rsmp_j = j * scale + k; // COLS: set i to i + scale pixels to value of m_ip->compiled[ i ] for ( h = 0; h < scale; h++ ) { rsmp_i = i * scale + h; // index into new mask pix = rsmp_j * ip->w + rsmp_i; if ( pix < r_sz ) { rsmp[ pix ] = m_ip->compiled[ j * m_ip->w + i ]; } } } } } if ( ip->bpp == 1 ) { for ( i = 0; i < (int)ip->numbytes; i += 1 ) { if ( rsmp[ i ] == 0 ) { ip->compiled[ i + 0 ] = 0; } } } else if ( 0 ) { // set to zero any texels that didn't pass for ( i = 0; i < (int)r_sz; i++ ) { if ( rsmp[ i ] == 0 ) { ip->compiled[ i * 4 + 0 ] = 0; ip->compiled[ i * 4 + 1 ] = 0; ip->compiled[ i * 4 + 2 ] = 0; ip->compiled[ i * 4 + 3 ] = 255; } } } // if bpp == 4 IMG_MakeGLTexture( ip ); } if ( ip->data ) { V_Free( ip->data ); ip->data = NULL; } if ( ip->compiled ) { V_Free( ip->compiled ); ip->compiled = NULL; } if ( m_ip->data ) { V_Free( m_ip->data ); m_ip->data = NULL; } if ( m_ip->compiled ) { V_Free( m_ip->compiled ); m_ip->compiled = NULL; } V_Free( m_ip ); if ( rsmp ) V_Free( rsmp ); *ipp = NULL; if ( err_cond ) return -4; *ipp = ip; return 0; }
void IMG_compileImageFile ( const char *path, image_t **ip ) { int type; int i; *ip = (image_t *) V_Malloc( sizeof(image_t) ); // get type from filename extension for (i = 0; path[i] != '\0'; i++) ; do { --i; } while ( path[i] != '.' ); ++i; type = IMG_NONE; if ( !C_strncasecmp( &path[i], "BMP", 3 ) ) type = IMG_BMP; else if ( !C_strncasecmp( &path[i], "TGA", 3 ) ) type = IMG_TGA; // switch(type) { case IMG_TGA: IMG_readfileTGA( path, *ip ); break; case IMG_BMP: IMG_readfileBMP( path, *ip ); break; case IMG_GIF: case IMG_JPG: case IMG_PCX: case IMG_PPM: case IMG_PNG: default: Com_Printf( "image type: %s not supported\n", IMG_Error(type) ); V_Free(*ip); (*ip)=NULL; return; } (*ip)->name[0] = 0; (*ip)->syspath[0] = 0; // get basename strcpy( (*ip)->name, strip_path( &path[0] ) ); // get relative name strcpy( (*ip)->syspath, strip_gamepath( &path[0] ) ); int err_cond = 0; if ( IMG_compileGLImage( *ip ) ) err_cond = 1; V_Free( (*ip)->data ); (*ip)->data = NULL; if ( !err_cond ) { IMG_MakeGLTexture( *ip ); V_Free( (*ip)->compiled ); (*ip)->compiled = NULL; } }