void FontGen::SaveTarga() { char fileName[256]; sprintf(fileName, "%s.tga", font_def.name); int start_line = TEX_HEIGHT - texture_height; WriteTGA(fileName, bmbits + TEX_WIDTH * 3 * start_line, TEX_WIDTH, texture_height, compressTga, monochrome); }
void WriteGlyphAsTGA(FT_Library &library, const std::string &fileName, wchar_t ch, FT_Face &face, int size, const Pixel32 &fontCol, const Pixel32 outlineCol, float outlineWidth) { // Set the size to use. if (FT_Set_Char_Size(face, size << 6, size << 6, 90, 90) == 0) { // Load the glyph we are looking for. FT_UInt gindex = FT_Get_Char_Index(face, ch); if (FT_Load_Glyph(face, gindex, FT_LOAD_NO_BITMAP) == 0) { // Need an outline for this to work. if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { // Render the basic glyph to a span list. Spans spans; RenderSpans(library, &face->glyph->outline, &spans); // Next we need the spans for the outline. Spans outlineSpans; // Set up a stroker. FT_Stroker stroker; FT_Stroker_New(library, &stroker); FT_Stroker_Set(stroker, (int)(outlineWidth * 64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); FT_Glyph glyph; if (FT_Get_Glyph(face->glyph, &glyph) == 0) { FT_Glyph_StrokeBorder(&glyph, stroker, 0, 1); // Again, this needs to be an outline to work. if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { // Render the outline spans to the span list FT_Outline *o = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline; RenderSpans(library, o, &outlineSpans); } // Clean up afterwards. FT_Stroker_Done(stroker); FT_Done_Glyph(glyph); // Now we need to put it all together. if (!spans.empty()) { // Figure out what the bounding rect is for both the span lists. Rect rect(spans.front().x, spans.front().y, spans.front().x, spans.front().y); for (Spans::iterator s = spans.begin(); s != spans.end(); ++s) { rect.Include(Vec2(s->x, s->y)); rect.Include(Vec2(s->x + s->width - 1, s->y)); } for (Spans::iterator s = outlineSpans.begin(); s != outlineSpans.end(); ++s) { rect.Include(Vec2(s->x, s->y)); rect.Include(Vec2(s->x + s->width - 1, s->y)); } #if 0 // This is unused in this test but you would need this to draw // more than one glyph. float bearingX = face->glyph->metrics.horiBearingX >> 6; float bearingY = face->glyph->metrics.horiBearingY >> 6; float advance = face->glyph->advance.x >> 6; #endif // Get some metrics of our image. int imgWidth = rect.Width(), imgHeight = rect.Height(), imgSize = imgWidth * imgHeight; // Allocate data for our image and clear it out to transparent. Pixel32 *pxl = new Pixel32[imgSize]; memset(pxl, 0, sizeof(Pixel32) * imgSize); // Loop over the outline spans and just draw them into the // image. for (Spans::iterator s = outlineSpans.begin(); s != outlineSpans.end(); ++s) for (int w = 0; w < s->width; ++w) pxl[(int)((imgHeight - 1 - (s->y - rect.ymin)) * imgWidth + s->x - rect.xmin + w)] = Pixel32(outlineCol.r, outlineCol.g, outlineCol.b, s->coverage); // Then loop over the regular glyph spans and blend them into // the image. for (Spans::iterator s = spans.begin(); s != spans.end(); ++s) for (int w = 0; w < s->width; ++w) { Pixel32 &dst = pxl[(int)((imgHeight - 1 - (s->y - rect.ymin)) * imgWidth + s->x - rect.xmin + w)]; Pixel32 src = Pixel32(fontCol.r, fontCol.g, fontCol.b, s->coverage); dst.r = (int)(dst.r + ((src.r - dst.r) * src.a) / 255.0f); dst.g = (int)(dst.g + ((src.g - dst.g) * src.a) / 255.0f); dst.b = (int)(dst.b + ((src.b - dst.b) * src.a) / 255.0f); dst.a = MIN(255, dst.a + src.a); } // Dump the image to disk. WriteTGA(fileName, pxl, imgWidth, imgHeight); delete [] pxl; } }
/* ----------------------------------------------------------------------------- Function: Parameters: Returns: Notes: ----------------------------------------------------------------------------- */ PRIVATE void R_ScreenShot_f( void ) { W8 *buffer; char picname[ 80 ]; char checkname[ MAX_OSPATH ]; int i; FILE *f; // create the scrnshots directory if it doesn't exist my_snprintf( checkname, sizeof( checkname ), "%s/scrnshot", FS_Gamedir() ); FS_CreateDirectory( checkname ); // // find a file name to save it to // my_strlcpy( picname, "scrn00.tga", sizeof( picname ) ); for( i = 0 ; i <= 99 ; ++i ) { picname[ 4 ] = i / 10 + '0'; picname[ 5 ] = i % 10 + '0'; my_snprintf( checkname, sizeof( checkname ), "%s/scrnshot/%s", FS_Gamedir(), picname ); f = fopen( checkname, "rb" ); if( ! f ) { break; // file doesn't exist } fclose( f ); } if( i == 100 ) { Com_Printf( "R_ScreenShot_f: Couldn't create a file\n" ); return; } buffer = MM_MALLOC( viddef.width * viddef.height * 3 ); pfglReadPixels( 0, 0, viddef.width, viddef.height, GL_RGB, GL_UNSIGNED_BYTE, buffer ); WriteTGA( checkname, 24, viddef.width, viddef.height, buffer, 1, 1 ); MM_FREE( buffer ); Com_Printf( "Wrote %s\n", picname ); }
/* ----------------------------------------------------------------------------- Function: SavePic() -Save graphic lump in targa image format. Parameters: chunk -[in] Chunk number to save. version -[in] extension version. 1 -WL6 2 -SOD Returns: Nothing. Notes: ----------------------------------------------------------------------------- */ PRIVATE void SavePic( W32 chunknum, W16 version, W8 *buffer, W8 *buffer2 ) { W16 i; W16 temp; char filename[32]; char *fname; W8 *ptr; W8 *pic; W32 picnum; W16 width, height; W16 linewidth, plane, sx, sy; W8 r,g,b; W16 rgb; W8 *tpalette = gamepal; static W16 offset = 0; if( ( (chunknum == WL1_N_BLANKPIC || chunknum == WL1_NOKEYPIC ) && (version & WL1_PAK) ) ) { return; } if( ( (chunknum == N_BLANKPIC || chunknum == NOKEYPIC ) && (version & WL6_PAK) ) ) { return; } if( ( (chunknum == SDM_N_BLANKPIC || chunknum == SDM_NOKEYPIC ) && (version & SDM_PAK) ) ) { return; } if( ( (chunknum == SOD_N_BLANKPIC || chunknum == SOD_NOKEYPIC ) && (version & SOD_PAK) ) ) { return; } // Spear used multiple palettes, so // pull out the one we need. if( version & SDM_PAK ) { switch( chunknum ) { case SDM_TITLE1PIC: case SDM_TITLE2PIC: CA_CacheGrChunk( SDM_TITLEPALETTE, version ); tpalette = grsegs[ SDM_TITLEPALETTE ]; break; default: tpalette = gamepal; break; } } if( version & SOD_PAK ) { switch( chunknum ) { case SOD_IDGUYS1PIC: case SOD_IDGUYS2PIC: CA_CacheGrChunk( SOD_IDGUYSPALETTE, version ); tpalette = grsegs[ SOD_IDGUYSPALETTE ]; break; case SOD_TITLE1PIC: case SOD_TITLE2PIC: CA_CacheGrChunk( SOD_TITLEPALETTE, version ); tpalette = grsegs[ SOD_TITLEPALETTE ]; break; case SOD_ENDSCREEN11PIC: CA_CacheGrChunk( SOD_END1PALETTE, version ); tpalette = grsegs[ SOD_END1PALETTE ]; break; case SOD_ENDSCREEN12PIC: CA_CacheGrChunk( SOD_END2PALETTE, version ); tpalette = grsegs[ SOD_END2PALETTE ]; break; case SOD_ENDSCREEN3PIC: CA_CacheGrChunk( SOD_END3PALETTE, version ); tpalette = grsegs[ SOD_END3PALETTE ]; break; case SOD_ENDSCREEN4PIC: CA_CacheGrChunk( SOD_END4PALETTE, version ); tpalette = grsegs[ SOD_END4PALETTE ]; break; case SOD_ENDSCREEN5PIC: CA_CacheGrChunk( SOD_END5PALETTE, version ); tpalette = grsegs[ SOD_END5PALETTE ]; break; case SOD_ENDSCREEN6PIC: CA_CacheGrChunk( SOD_END6PALETTE, version ); tpalette = grsegs[ SOD_END6PALETTE ]; break; case SOD_ENDSCREEN7PIC: CA_CacheGrChunk( SOD_END7PALETTE, version ); tpalette = grsegs[ SOD_END7PALETTE ]; break; case SOD_ENDSCREEN8PIC: CA_CacheGrChunk( SOD_END8PALETTE, version ); tpalette = grsegs[ SOD_END8PALETTE ]; break; case SOD_ENDSCREEN9PIC: CA_CacheGrChunk( SOD_END9PALETTE, version ); tpalette = grsegs[ SOD_END9PALETTE ]; break; default: tpalette = gamepal; break; } // End switch chunknum } // End if version & SOD_PAK STATUSBARHACK: picnum = chunknum - STARTPICS; pic = grsegs[ chunknum ]; width = pictable[ picnum ].width; height= pictable[ picnum ].height; linewidth = width / 4; for( i = 0; i < ( width * height ); ++i, pic++ ) { plane = i / ( (width * height) / 4 ); sx = ( ( i % ( linewidth ) ) * 4 ) + plane; sy = ( ( i / linewidth ) % height ); ptr = buffer + ( (sx*2) + (sy * width)*2); temp = (*pic) * 3; r = tpalette[ temp ] >> 1; g = tpalette[ temp+1 ]; b = tpalette[ temp+2 ] >> 1; rgb = (b << 11) | (g << 5) | r; ptr[ 0 ] = rgb & 0xff; ptr[ 1 ] = rgb >> 8; } // // Hacks to reassemble images // if( version & WL1_PAK ) { if( chunknum == WL1_STATUSBARPIC ) { memcpy( buffer2, buffer, width * height * 2 ); // Save Status bar pic CA_CacheGrChunk( WL1_NOKEYPIC, version ); // cache NOKEYPIC chunknum = WL1_NOKEYPIC; goto STATUSBARHACK; } else if( chunknum == WL1_H_BOTTOMINFOPIC ) { MergeImages( buffer, 2, 304, 91, 16, 24, 4, buffer2, 2, 91, 91, 16, 0, 0 ); MergeImages( buffer, 2, 304, 91, 16, 192, 4, buffer2, 2, 91, 91, 16, 0, 16 ); hq2x_32( buffer2, buffer, 91, 16, (91*2)*4 ); RGB32toRGB24( buffer, buffer, 182*32*4 ); cs_snprintf( filename, sizeof( filename ), "%s/%s.tga", LGFXDIR, "PLAQUE_PAGE" ); WriteTGA( filename, 24, 182, 32, buffer, 0, 0 ); hq2x_32( buffer2 + (16 * 91 * 2), buffer, 91, 16, (91*2)*4 ); RGB32toRGB24( buffer, buffer, 182*32*4 ); cs_snprintf( filename, sizeof( filename ), "%s/%s.tga", LGFXDIR, "PLAQUE_BLANK" ); WriteTGA( filename, 24, 182, 32, buffer, 0, 1 ); return; } else if( chunknum == WL1_NOKEYPIC ) { chunknum = WL1_STATUSBARPIC; MergePics( buffer, buffer2, width, height, 2, 320, 240, 4 ); MergePics( buffer, buffer2, width, height, 2, 320, 240, 4+height ); memcpy( buffer, buffer2, 320 * 40 * 2 ); width = 320; height = 40; } else if( chunknum == WL1_L_COLONPIC ) { memset( buffer2, 0, 256*64*2 ); MergePics( buffer, buffer2, width, height, 2, 256, 160, 16 ); return; } else if( chunknum == WL1_L_EXPOINTPIC ) { MergePics( buffer, buffer2, width, height, 2, 256, 16, 0 ); return; } else if( chunknum == WL1_L_APOSTROPHEPIC ) { W16 i; MergePics( buffer, buffer2, width, height, 2, 256, 112, 0 ); memcpy( buffer, buffer2, 256 * 64 * 2 ); for( i = 0 ; i < 256 * 64 * 2 ; i += 2 ) { if( buffer[ i ] == 0 && buffer[ i + 1 ] == 0 ) { buffer[ i + 1 ] = 66; } } offset = 0; width = 256; height = 64; } else if( chunknum == WL1_L_PERCENTPIC ) { offset = 16; // this is for L_APIC... MergePics( buffer, buffer2, width, height, 2, 256, 80, 0 ); return; } else if( chunknum >= WL1_L_NUM0PIC && chunknum <= WL1_L_NUM9PIC ) { MergePics( buffer, buffer2, width, height, 2, 256, offset, 16 ); offset += width; return; } else if( chunknum >= WL1_N_0PIC && chunknum < WL1_N_9PIC ) { MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 ); offset += width + 1; return; } else if( chunknum == WL1_N_9PIC ) { W32 i; MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 ); memcpy( buffer, buffer2, 90 * height * 2 ); for( i = 0 ; i < 90 * 16 * 2 ; i += 2 ) { if( ! (i % 9) && i != 0 ) { buffer[ i - 2 ] = 0; buffer[ i - 1 ] = 160; } } width = 90; offset = 0; } else if( chunknum >= WL1_L_APIC && chunknum <= WL1_L_ZPIC ) { static W32 yoffset = 32; MergePics( buffer, buffer2, width, height, 2, 256, offset, yoffset ); offset += width; if( offset >= 256 ) { offset = 0; yoffset += 16; } return; } else if( chunknum == WL1_FACE5CPIC ) { // hmmm... Why is this one messed up? MergeImages( buffer, 2, 24, 18, height-2, 8, 2, buffer2, 2, 24, 18, height-2, 0, 0 ); MergeImages( buffer, 2, 24, 8, height-3, 0, 3, buffer2, 2, 24, 8, height-2, 16, 0 ); MergeImages( buffer, 2, 24, 18, 2, 9, 0, buffer2, 2, 24, 18, 2, 0, height-2 ); MergeImages( buffer, 2, 24, 7, 3, 1, 0, buffer2, 2, 24, 7, 3, 16, height-3 ); memcpy( buffer, buffer2, 24 * 32 * 2 ); buffer[ (30 * 24 * 2) + (3 * 2) ] = 73; buffer[ (30 * 24 * 2) + (3 * 2) + 1 ] = 74; buffer[ (31 * 24 * 2) + (3 * 2) ] = 73; buffer[ (31 * 24 * 2) + (3 * 2) + 1 ] = 74; buffer[ (29 * 24 * 2) + (23 * 2) ] = 73; buffer[ (29 * 24 * 2) + (23 * 2) + 1 ] = 74; buffer[ (30 * 24 * 2) + (23 * 2) ] = 73; buffer[ (30 * 24 * 2) + (23 * 2) + 1 ] = 74; buffer[ (31 * 24 * 2) + (23 * 2) ] = 73; buffer[ (31 * 24 * 2) + (23 * 2) + 1 ] = 74; buffer[ (29 * 24 * 2) + (19 * 2) ] = 255; buffer[ (29 * 24 * 2) + (19 * 2) + 1 ] = 100; buffer[ (30 * 24 * 2) + (19 * 2) ] = 63; buffer[ (30 * 24 * 2) + (19 * 2) + 1 ] = 117; buffer[ (31 * 24 * 2) + (19 * 2) ] = 52; buffer[ (31 * 24 * 2) + (19 * 2) + 1 ] = 59; buffer[ (30 * 24 * 2) + (7 * 2) ] = 19; buffer[ (30 * 24 * 2) + (7 * 2) + 1 ] = 59; buffer[ (31 * 24 * 2) + (7 * 2) ] = 19; buffer[ (31 * 24 * 2) + (7 * 2) + 1 ] = 59; buffer[ (30 * 24 * 2) + (11 * 2) ] = 91; buffer[ (30 * 24 * 2) + (11 * 2) + 1 ] = 84; buffer[ (31 * 24 * 2) + (11 * 2) ] = 190; buffer[ (31 * 24 * 2) + (11 * 2) + 1 ] = 92; buffer[ (30 * 24 * 2) + (15 * 2) ] = 249; buffer[ (30 * 24 * 2) + (15 * 2) + 1 ] = 75; buffer[ (31 * 24 * 2) + (15 * 2) ] = 190; buffer[ (31 * 24 * 2) + (15 * 2) + 1 ] = 92; } } else if( version & WL6_PAK ) { if( chunknum == STATUSBARPIC ) { memcpy( buffer2, buffer, width * height * 2 ); // Save Status bar pic CA_CacheGrChunk( NOKEYPIC, version ); // cache NOKEYPIC chunknum = NOKEYPIC; goto STATUSBARHACK; } else if( chunknum == H_BOTTOMINFOPIC ) { MergeImages( buffer, 2, 304, 91, 16, 24, 4, buffer2, 2, 91, 91, 16, 0, 0 ); MergeImages( buffer, 2, 304, 91, 16, 192, 4, buffer2, 2, 91, 91, 16, 0, 16 ); hq2x_32( buffer2, buffer, 91, 16, (91*2)*4 ); RGB32toRGB24( buffer, buffer, 182*32*4 ); cs_snprintf( filename, sizeof( filename ), "%s/%s.tga", LGFXDIR, "PLAQUE_PAGE" ); WriteTGA( filename, 24, 182, 32, buffer, 0, 0 ); hq2x_32( buffer2 + (16 * 91 * 2), buffer, 91, 16, (91*2)*4 ); RGB32toRGB24( buffer, buffer, 182*32*4 ); cs_snprintf( filename, sizeof( filename ), "%s/%s.tga", LGFXDIR, "PLAQUE_BLANK" ); WriteTGA( filename, 24, 182, 32, buffer, 0, 1 ); return; } else if( chunknum == NOKEYPIC ) { chunknum = STATUSBARPIC; MergePics( buffer, buffer2, width, height, 2, 320, 240, 4 ); MergePics( buffer, buffer2, width, height, 2, 320, 240, 4+height ); memcpy( buffer, buffer2, 320 * 40 * 2 ); width = 320; height = 40; } else if( chunknum == L_COLONPIC ) { memset( buffer2, 0, 256*64*2 ); MergePics( buffer, buffer2, width, height, 2, 256, 160, 16 ); return; } else if( chunknum == L_EXPOINTPIC ) { MergePics( buffer, buffer2, width, height, 2, 256, 16, 0 ); return; } else if( chunknum == L_APOSTROPHEPIC ) { W16 i; MergePics( buffer, buffer2, width, height, 2, 256, 112, 0 ); memcpy( buffer, buffer2, 256 * 64 * 2 ); for( i = 0 ; i < 256 * 64 * 2 ; i += 2 ) { if( buffer[ i ] == 0 && buffer[ i + 1 ] == 0 ) { buffer[ i + 1 ] = 66; } } offset = 0; width = 256; height = 64; } else if( chunknum == L_PERCENTPIC ) { offset = 16; // this is for L_APIC... MergePics( buffer, buffer2, width, height, 2, 256, 80, 0 ); return; } else if( chunknum >= L_NUM0PIC && chunknum <= L_NUM9PIC ) { MergePics( buffer, buffer2, width, height, 2, 256, offset, 16 ); offset += width; return; } else if( chunknum >= N_0PIC && chunknum < N_9PIC ) { MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 ); offset += width + 1; return; } else if( chunknum == N_9PIC ) { W32 i; MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 ); memcpy( buffer, buffer2, 90 * height * 2 ); for( i = 0 ; i < 90 * 16 * 2 ; i += 2 ) { if( ! (i % 9) && i != 0 ) { buffer[ i - 2 ] = 0; buffer[ i - 1 ] = 160; } } width = 90; offset = 0; } else if( chunknum >= L_APIC && chunknum <= L_ZPIC ) { static W32 yoffset = 32; MergePics( buffer, buffer2, width, height, 2, 256, offset, yoffset ); offset += width; if( offset >= 256 ) { offset = 0; yoffset += 16; } return; } } else if( version & SDM_PAK ) { if( chunknum == SDM_STATUSBARPIC ) { memcpy( buffer2, buffer, width * height * 2 ); // Save Status bar pic CA_CacheGrChunk( SDM_NOKEYPIC, version ); // cache SOD_NOKEYPIC chunknum = SDM_NOKEYPIC; goto STATUSBARHACK; } else if( chunknum == SDM_NOKEYPIC ) { chunknum = SDM_STATUSBARPIC; MergePics( buffer, buffer2, width, height, 2, 320, 240, 4 ); MergePics( buffer, buffer2, width, height, 2, 320, 240, 4+height ); memcpy( buffer, buffer2, 320 * 40 * 2 ); width = 320; height = 40; } else if( chunknum == SDM_L_COLONPIC ) { memset( buffer2, 0, 256*64*2 ); MergePics( buffer, buffer2, width, height, 2, 256, 160, 16 ); return; } else if( chunknum == SDM_L_EXPOINTPIC ) { MergePics( buffer, buffer2, width, height, 2, 256, 16, 0 ); return; } else if( chunknum == SDM_L_APOSTROPHEPIC ) { W16 i; MergePics( buffer, buffer2, width, height, 2, 256, 112, 0 ); memcpy( buffer, buffer2, 256 * 64 * 2 ); for( i = 0 ; i < 256 * 64 * 2 ; i += 2 ) { if( buffer[ i ] == 0 && buffer[ i + 1 ] == 0 ) { buffer[ i + 1 ] = 66; } } offset = 0; width = 256; height = 64; } else if( chunknum == SDM_L_PERCENTPIC ) { offset = 16; // this is for L_APIC... MergePics( buffer, buffer2, width, height, 2, 256, 80, 0 ); return; } else if( chunknum >= SDM_L_NUM0PIC && chunknum <= SDM_L_NUM9PIC ) { MergePics( buffer, buffer2, width, height, 2, 256, offset, 16 ); offset += width; return; } else if( chunknum >= SDM_N_0PIC && chunknum < SDM_N_9PIC ) { MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 ); offset += width + 1; return; } else if( chunknum == SDM_N_9PIC ) { W32 i; MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 ); memcpy( buffer, buffer2, 90 * height * 2 ); for( i = 0 ; i < 90 * 16 * 2 ; i += 2 ) { if( ! (i % 9) && i != 0 ) { buffer[ i - 2 ] = 0; buffer[ i - 1 ] = 160; } } width = 90; offset = 0; } else if( chunknum >= SDM_L_APIC && chunknum <= SDM_L_ZPIC ) { static W32 yoffset = 32; MergePics( buffer, buffer2, width, height, 2, 256, offset, yoffset ); offset += width; if( offset >= 256 ) { offset = 0; yoffset += 16; } return; } else if( chunknum == SDM_TITLE1PIC ) { memcpy( buffer2+offset, buffer, (width*height*2) ); offset += width*height*2; return; } else if( chunknum == SDM_TITLE2PIC ) { memcpy( buffer2+offset, buffer, (width*height*2) ); memcpy( buffer, buffer2, 320*200*2 ); height = 200; offset = 0; } } else if( version & SOD_PAK ) { if( chunknum == SOD_STATUSBARPIC ) { memcpy( buffer2, buffer, width * height * 2 ); // Save Status bar pic CA_CacheGrChunk( SOD_NOKEYPIC, version ); // cache SOD_NOKEYPIC chunknum = SOD_NOKEYPIC; goto STATUSBARHACK; } else if( chunknum == SOD_NOKEYPIC ) { chunknum = SOD_STATUSBARPIC; MergePics( buffer, buffer2, width, height, 2, 320, 240, 4 ); MergePics( buffer, buffer2, width, height, 2, 320, 240, 4+height ); memcpy( buffer, buffer2, 320 * 40 * 2 ); width = 320; height = 40; } else if( chunknum == SOD_L_COLONPIC ) { memset( buffer2, 0, 256*64*2 ); MergePics( buffer, buffer2, width, height, 2, 256, 160, 16 ); return; } else if( chunknum == SOD_L_EXPOINTPIC ) { MergePics( buffer, buffer2, width, height, 2, 256, 16, 0 ); return; } else if( chunknum == SOD_L_APOSTROPHEPIC ) { W16 i; MergePics( buffer, buffer2, width, height, 2, 256, 112, 0 ); memcpy( buffer, buffer2, 256 * 64 * 2 ); for( i = 0 ; i < 256 * 64 * 2 ; i += 2 ) { if( buffer[ i ] == 0 && buffer[ i + 1 ] == 0 ) { buffer[ i + 1 ] = 66; } } offset = 0; width = 256; height = 64; } else if( chunknum == SOD_L_PERCENTPIC ) { offset = 16; // this is for L_APIC... MergePics( buffer, buffer2, width, height, 2, 256, 80, 0 ); return; } else if( chunknum >= SOD_L_NUM0PIC && chunknum <= SOD_L_NUM9PIC ) { MergePics( buffer, buffer2, width, height, 2, 256, offset, 16 ); offset += width; return; } else if( chunknum >= SOD_N_0PIC && chunknum < SOD_N_9PIC ) { MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 ); offset += width + 1; return; } else if( chunknum == SOD_N_9PIC ) { W32 i; MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 ); memcpy( buffer, buffer2, 90 * height * 2 ); for( i = 0 ; i < 90 * 16 * 2 ; i += 2 ) { if( ! (i % 9) && i != 0 ) { buffer[ i - 2 ] = 0; buffer[ i - 1 ] = 160; } } width = 90; offset = 0; } else if( chunknum >= SOD_L_APIC && chunknum <= SOD_L_ZPIC ) { static W32 yoffset = 32; MergePics( buffer, buffer2, width, height, 2, 256, offset, yoffset ); offset += width; if( offset >= 256 ) { offset = 0; yoffset += 16; } return; } else if( chunknum == SOD_IDGUYS1PIC ) { memcpy( buffer2+offset, buffer, (width*height*2) ); offset += width*height*2; return; } else if( chunknum == SOD_IDGUYS2PIC ) { memcpy( buffer2+offset, buffer, (width*height*2) ); memcpy( buffer, buffer2, 320*200*2 ); height = 200; offset = 0; } else if( chunknum == SOD_TITLE1PIC ) { memcpy( buffer2+offset, buffer, (width*height*2) ); offset += width*height*2; return; } else if( chunknum == SOD_TITLE2PIC ) { memcpy( buffer2+offset, buffer, (width*height*2) ); memcpy( buffer, buffer2, 320*200*2 ); height = 200; offset = 0; } } // // End of images hacks // if( version & WL1_PAK ) { fname = GetLumpFileName_WL1( chunknum ); } else if( version & WL6_PAK ) { fname = GetLumpFileName_WL6( chunknum ); } else if( version & SDM_PAK ) { fname = GetLumpFileName_SDM( chunknum ); } else if( version & SOD_PAK ) { fname = GetLumpFileName_SOD( chunknum ); } else { printf( "Unknown file extension!\n" ); return; } if( fname == NULL ) { printf( "File name not found for item: (%d)\n", chunknum ); return; } cs_snprintf( filename, sizeof( filename ), "%s/%s.tga", LGFXDIR, fname ); hq2x_32( buffer, buffer2, width, height, (width*2)*4 ); // Get rid of alpha channel RGB32toRGB24( buffer2, buffer2, (width*2)*(height*2)*4 ); WriteTGA( filename, 24, (width*2), (height*2), buffer2, 0, 1 ); return; }
/* ----------------------------------------------------------------------------- Function: Fontline() -Extract and save font. Parameters: fontnumber -[in] font to save. version -[in] extension version. 1 -WL6 2 -SOD Returns: Nothing. Notes: Font must be cached in grsegs[] before calling. ----------------------------------------------------------------------------- */ PRIVATE void Fontline( W32 fontnumber, W16 version ) { fontstruct *font; W16 i; W16 x, y; W16 px, py; W8 *buffer; W8 *source; W8 *ptr; char filename[ 256 ]; font = (fontstruct *)grsegs[ fontnumber ]; buffer = MM_MALLOC( FONTWIDTH * FONTHEIGHT * 4 ); if( buffer == NULL ) return; ptr = buffer; for( x = 0; x < FONTWIDTH; ++x ) { for( y = 0; y < FONTHEIGHT; ++y, ptr += 4 ) { ptr[ 0 ] = ptr[ 1 ] = ptr[ 2 ] = 0xFF; ptr[ 3 ] = 0x00; } } px = py = 0; for( i = 0; i < 256; ++i ) { if( ! font->width[ i ] ) continue; if( px + font->width[ i ] > FONTWIDTH-1 ) { py += font->height; px = 0; } source = ((PW8) font) + font->location[ i ]; ptr = buffer + (py * FONTWIDTH + px) * 4; for( y = 0; y < font->height; ++y, ptr += FONTWIDTH * 4 ) { for( x = 0; x < font->width[ i ]; ++x ) { if( *source++ ) { ptr[ x * 4 + 3 ] = 0xFF; } } } px += 16; } // end for i = 0; i < 256; ++i cs_snprintf( filename, sizeof( filename ), "%s/font%d.tga", LGFXDIR, fontnumber ); WriteTGA( filename, 32, FONTWIDTH, FONTHEIGHT, buffer, 0, 1 ); MM_FREE( buffer ); }
int main( int argc, char * argv[] ) { printf( "networked physics demo\n" ); bool shadows = true; bool playback = false; bool video = false; for ( int i = 1; i < argc; ++i ) { if ( strcmp( argv[i], "playback" ) == 0 ) { printf( "playback\n" ); playback = true; } else if ( strcmp( argv[i], "video" ) == 0 ) { printf( "video\n" ); video = true; } } net::InitializeSockets(); while ( !net::IsInitialized() ) { printf( "error: failed to initialize sockets\n" ); net::ShutdownSockets(); return 1; } #ifndef PROFILE int displayWidth, displayHeight; GetDisplayResolution( displayWidth, displayHeight ); #ifdef LETTERBOX displayWidth = 1280; displayHeight = 800; #endif printf( "display resolution is %d x %d\n", displayWidth, displayHeight ); HideMouseCursor(); if ( !OpenDisplay( "Networked Physics", displayWidth, displayHeight ) ) { printf( "error: failed to open display" ); return 1; } #endif int currentDemo = 0; Demo * demo = CreateDemo( 0 ); assert( demo ); demo->InitializeWorld(); renderInterface = new render::Interface( displayWidth, displayHeight ); #ifndef PROFILE demo->SetRenderInterface( renderInterface ); #endif uint32_t frame = 0; // create 2 pixel buffer objects, you need to delete them when program exits. // glBufferDataARB with NULL pointer reserves only memory space. const int NumPBOs = 2; GLuint pboIds[NumPBOs]; int index = 0; const int dataSize = displayWidth * displayHeight * 3; if ( video ) { glGenBuffersARB( NumPBOs, pboIds ); for ( int i = 0; i < NumPBOs; ++i ) { glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, pboIds[i] ); glBufferDataARB( GL_PIXEL_UNPACK_BUFFER_ARB, dataSize, 0, GL_STREAM_DRAW_ARB ); } glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, 0 ); } // record input to a file // read it back in playback mode for recording video FILE * inputFile = fopen( "output/recordedInputs", playback ? "rb" : "wb" ); if ( !inputFile ) { printf( "failed to open input file\n" ); return 1; } bool quit = false; while ( !quit ) { #ifdef PROFILE printf( "profiling frame %d\n", frame ); #endif platform::Input input; if ( !playback ) { input = platform::Input::Sample(); fwrite( &input, sizeof( platform::Input ), 1, inputFile ); fflush( inputFile ); } else { const int size = sizeof( platform::Input ); if ( !fread( &input, size, 1, inputFile ) ) quit = true; } #ifdef PROFILE if ( frame > 500 ) input.left = frame % 2; else if ( frame > 100 && ( frame % 5 ) == 0 ) input.left = true; input.z = true; #endif if ( input.alt ) { int demoIndex = -1; if ( input.one ) demoIndex = 0; if ( input.two ) demoIndex = 1; if ( input.three ) demoIndex = 2; if ( input.four ) demoIndex = 3; if ( input.five ) demoIndex = 4; if ( input.six ) demoIndex = 5; if ( input.seven ) demoIndex = 6; if ( input.eight ) demoIndex = 7; if ( input.nine ) demoIndex = 8; if ( input.zero ) demoIndex = 9; static bool enterDownLastFrame = false; if ( input.enter && !enterDownLastFrame ) shadows = !shadows; enterDownLastFrame = input.enter; if ( demoIndex != -1 ) { Demo * newDemo = CreateDemo( demoIndex ); if ( newDemo ) { #ifndef PROFILE renderInterface->ClearScreen(); #ifdef LETTERBOX renderInterface->LetterBox( 80 ); #endif UpdateDisplay( 1 ); #endif delete demo; demo = newDemo; assert( demo ); demo->InitializeWorld(); #ifndef PROFILE demo->SetRenderInterface( renderInterface ); #endif currentDemo = demoIndex; } } } static bool escapeDownLastFrame = false; if ( input.escape && !escapeDownLastFrame ) { #ifndef PROFILE renderInterface->ClearScreen(); #ifdef LETTERBOX renderInterface->LetterBox( 80 ); #endif UpdateDisplay( 1 ); #endif delete demo; demo = CreateDemo( currentDemo ); assert( demo ); demo->InitializeWorld(); #ifndef PROFILE demo->SetRenderInterface( renderInterface ); #endif } escapeDownLastFrame = input.escape; demo->ProcessInput( !input.alt ? input : platform::Input() ); demo->Update( DeltaTime ); if ( video ) { // "index" is used to read pixels from framebuffer to a PBO // "nextIndex" is used to update pixels in the other PBO index = ( index + 1 ) % NumPBOs; int prevIndex = ( index + NumPBOs - 1 ) % NumPBOs; // set the target framebuffer to read glReadBuffer( GL_FRONT ); // read pixels from framebuffer to PBO // glReadPixels() should return immediately. glBindBufferARB( GL_PIXEL_PACK_BUFFER_ARB, pboIds[index] ); glReadPixels( 0, 0, displayWidth, displayHeight, GL_BGR, GL_UNSIGNED_BYTE, 0 ); if ( frame > (unsigned) NumPBOs ) { // map the PBO to process its data by CPU glBindBufferARB( GL_PIXEL_PACK_BUFFER_ARB, pboIds[prevIndex] ); GLubyte * ptr = (GLubyte*) glMapBufferARB( GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB ); if ( ptr ) { char filename[256]; sprintf( filename, "output/frame-%05d.tga", frame - NumPBOs ); #ifdef LETTERBOX WriteTGA( filename, displayWidth, displayHeight - 80, ptr + displayWidth * 3 * 40 ); #else WriteTGA( filename, displayWidth, displayHeight, ptr ); #endif glUnmapBufferARB( GL_PIXEL_PACK_BUFFER_ARB ); } } // back to conventional pixel operation glBindBufferARB( GL_PIXEL_PACK_BUFFER_ARB, 0 ); } demo->WaitForSim(); #ifndef PROFILE demo->Render( DeltaTime, shadows ); #ifdef LETTERBOX renderInterface->LetterBox( 80 ); #endif UpdateDisplay( video ? 0 : 1 ); #endif frame ++; } #ifndef PROFILE CloseDisplay(); #endif delete demo; delete renderInterface; printf( "shutdown\n" ); net::ShutdownSockets(); return 0; }
image_t *ImageLoad( const char *filename ) { int i; image_t *image; char name[ 1024 ]; int size; byte *buffer = NULL; qboolean alphaHack = qfalse; /* init */ ImageInit(); /* dummy check */ if( filename == NULL || filename[ 0 ] == '\0' ) return NULL; /* strip file extension off name */ strcpy( name, filename ); StripExtension( name ); /* try to find existing image */ image = ImageFind( name ); if( image != NULL ) { image->refCount++; return image; } /* none found, so find first non-null image */ image = NULL; for( i = 0; i < MAX_IMAGES; i++ ) { if( images[ i ].name == NULL ) { image = &images[ i ]; break; } } /* too many images? */ if( image == NULL ) Error( "MAX_IMAGES (%d) exceeded, there are too many image files referenced by the map.", MAX_IMAGES ); /* set it up */ image->name = safe_malloc( strlen( name ) + 1 ); strcpy( image->name, name ); /* attempt to load tga */ StripExtension( name ); strcat( name, ".tga" ); size = vfsLoadFile( (const char*) name, (void**) &buffer, 0 ); if( size > 0 ) LoadTGABuffer( buffer, buffer + size, &image->pixels, &image->width, &image->height ); else { /* attempt to load png */ StripExtension( name ); strcat( name, ".png" ); size = vfsLoadFile( (const char*) name, (void**) &buffer, 0 ); if( size > 0 ) LoadPNGBuffer( buffer, size, &image->pixels, &image->width, &image->height ); else { /* attempt to load jpg */ StripExtension( name ); strcat( name, ".jpg" ); size = vfsLoadFile( (const char*) name, (void**) &buffer, 0 ); if( size > 0 ) { if( LoadJPGBuff( buffer, size, &image->pixels, &image->width, &image->height ) == -1 && image->pixels != NULL ) Sys_Printf( "WARNING: LoadJPGBuff: %s\n", (unsigned char*) image->pixels ); alphaHack = qtrue; } else { /* attempt to load dds */ StripExtension( name ); strcat( name, ".dds" ); size = vfsLoadFile( (const char*) name, (void**) &buffer, 0 ); if( size > 0 ) { LoadDDSBuffer( buffer, size, &image->pixels, &image->width, &image->height ); /* debug code */ #if 1 { ddsPF_t pf; DDSGetInfo( (ddsBuffer_t*) buffer, NULL, NULL, &pf ); Sys_Printf( "pf = %d\n", pf ); if( image->width > 0 ) { StripExtension( name ); strcat( name, "_converted.tga" ); WriteTGA( "C:\\games\\quake3\\baseq3\\textures\\rad\\dds_converted.tga", image->pixels, image->width, image->height ); } } #endif } } } } /* free file buffer */ free( buffer ); /* make sure everything's kosher */ if( size <= 0 || image->width <= 0 || image->height <= 0 || image->pixels == NULL ) { //% Sys_Printf( "size = %d width = %d height = %d pixels = 0x%08x (%s)\n", //% size, image->width, image->height, image->pixels, name ); free( image->name ); image->name = NULL; return NULL; } /* set filename */ image->filename = safe_malloc( strlen( name ) + 1 ); strcpy( image->filename, name ); /* set count */ image->refCount = 1; numImages++; if(alphaHack) { StripExtension( name ); strcat( name, "_alpha.jpg" ); size = vfsLoadFile( (const char*) name, (void**) &buffer, 0 ); if( size > 0 ) { unsigned char *pixels; int width, height; if( LoadJPGBuff( buffer, size, &pixels, &width, &height ) == -1 && pixels != NULL ) Sys_Printf( "WARNING: LoadJPGBuff: %s\n", (unsigned char*) image->pixels ); if(pixels && width == image->width && height == image->height) { int i; for(i = 0; i < width*height; ++i) image->pixels[4*i+3] = pixels[4*i+2]; // copy alpha from blue channel } free(pixels); free(buffer); } } /* return the image */ return image; }
void CImage::WriteTGA (const char *dir, const char *filename) { string path = dir; path += SEP; path += filename; WriteTGA (path.c_str()); }
/* ============== WriteRenderBump ============== */ static void WriteRenderBump( renderBump_t *rb, int outLinePixels ) { int width, height; int i; idStr filename; renderModelManager->FreeModel( rb->highModel ); FreeTriHash( rb->hash ); width = rb->width; height = rb->height; #if 0 // save the non-outlined version filename = source; filename.setFileExtension(); filename.append( "_nooutline.tga" ); common->Printf( "writing %s\n", filename.c_str() ); WriteTGA( filename, globalPic, width, height ); #endif // outline the image several times to help bilinear filtering across disconnected // edges, and mip-mapping for ( i = 0 ; i < outLinePixels ; i++ ) { OutlineNormalMap( rb->localPic, width, height, 128, 128, 128 ); OutlineNormalMap( rb->globalPic, width, height, 128, 128, 128 ); OutlineColorMap( rb->colorPic, width, height, 128, 128, 128 ); } // filter down if we are anti-aliasing for ( i = 0 ; i < rb->antiAlias ; i++ ) { byte *old; old = rb->localPic; rb->localPic = R_MipMap( rb->localPic, width, height, false ); Mem_Free( old ); old = rb->globalPic; rb->globalPic = R_MipMap( rb->globalPic, width, height, false ); Mem_Free( old ); old = rb->colorPic; rb->colorPic = R_MipMap( rb->colorPic, width, height, false ); Mem_Free( old ); width >>= 1; height >>= 1; } // write out the local map filename = rb->outputName; filename.SetFileExtension( ".tga" ); common->Printf( "writing %s (%i,%i)\n", filename.c_str(), width, height ); R_WriteTGA( filename, rb->localPic, width, height ); if ( rb->saveGlobalMap ) { filename = rb->outputName; filename.StripFileExtension(); filename.Append( "_global.tga" ); common->Printf( "writing %s (%i,%i)\n", filename.c_str(), width, height ); R_WriteTGA( filename, rb->globalPic, width, height ); } if ( rb->saveColorMap ) { filename = rb->outputName; filename.StripFileExtension(); filename.Append( "_color.tga" ); common->Printf( "writing %s (%i,%i)\n", filename.c_str(), width, height ); R_WriteTGA( filename, rb->colorPic, width, height ); } Mem_Free( rb->localPic ); Mem_Free( rb->globalPic ); Mem_Free( rb->colorPic ); Mem_Free( rb->edgeDistances ); }
image_t *ImageLoad(const char *filename) { int i; image_t *image; char name[1024]; int size; byte *buffer = NULL; /* init */ ImageInit(); /* dummy check */ if(filename == NULL || filename[0] == '\0') return NULL; /* strip file extension off name */ strcpy(name, filename); StripExtension(name); /* try to find existing image */ image = ImageFind(name); if(image != NULL) { image->refCount++; return image; } /* none found, so find first non-null image */ image = NULL; for(i = 0; i < MAX_IMAGES; i++) { if(images[i].name == NULL) { image = &images[i]; break; } } /* too many images? */ if(image == NULL) Error("MAX_IMAGES (%d) exceeded, there are too many image files referenced by the map.", MAX_IMAGES); /* set it up */ image->name = safe_malloc(strlen(name) + 1); strcpy(image->name, name); #if 1 /* attempt to load tga */ StripExtension(name); strcat(name, ".tga"); size = vfsLoadFile((const char *)name, (void **)&buffer, 0); if(size > 0) LoadTGABuffer(buffer, &image->pixels, &image->width, &image->height); else { #if 1 /* attempt to load png */ StripExtension(name); strcat(name, ".png"); size = vfsLoadFile((const char *)name, (void **)&buffer, 0); if(size > 0) LoadPNGBuffer(buffer, &image->pixels, &image->width, &image->height); else { #if 1 /* attempt to load jpg */ StripExtension(name); strcat(name, ".jpg"); size = vfsLoadFile((const char *)name, (void **)&buffer, 0); if(size > 0) { LoadJPGBuffer((const char *)name, buffer, size, &image->pixels, &image->width, &image->height); if(image->pixels == NULL) Sys_Printf("WARNING: LoadJPGBuffer: '%s'\n", image->name); } else { #if 1 /* attempt to load dds */ StripExtension(name); strcat(name, ".dds"); size = vfsLoadFile((const char *)name, (void **)&buffer, 0); if(size > 0) { LoadDDSBuffer(buffer, size, &image->pixels, &image->width, &image->height); /* debug code */ #if 0 { ddsPF_t pf; DDSGetInfo((ddsBuffer_t *) buffer, NULL, NULL, &pf); Sys_Printf("pf = %d\n", pf); if(image->width > 0) { StripExtension(name); strcat(name, "_converted.tga"); WriteTGA("C:\\games\\quake3\\baseq3\\textures\\rad\\dds_converted.tga", image->pixels, image->width, image->height); } } #endif // dds debug } #endif // ignore dds } #endif // ignore jpg dds } #endif // ignore png jpg dds } #endif // ignore all images /* free file buffer */ free(buffer); /* make sure everything's kosher */ if(size <= 0 || image->width <= 0 || image->height <= 0 || image->pixels == NULL) { //% Sys_Printf( "size = %d width = %d height = %d pixels = 0x%08x (%s)\n", //% size, image->width, image->height, image->pixels, name ); free(image->name); image->name = NULL; return NULL; } /* set filename */ image->filename = safe_malloc(strlen(name) + 1); strcpy(image->filename, name); /* set count */ image->refCount = 1; numImages++; /* return the image */ return image; }