CVertMeshViewer::CVertMeshViewer(UVertMesh* Mesh, CApplication* Window) : CMeshViewer(Mesh, Window) , AnimIndex(-1) { CVertMeshInstance *VertInst = new CVertMeshInstance(); VertInst->SetMesh(Mesh); Inst = VertInst; CVertMeshInstance *MeshInst = static_cast<CVertMeshInstance*>(Inst); // compute model center by Z-axis (vertical) CVec3 offset; const FBox &B = Mesh->BoundingBox; #if 1 VectorAdd(CVT(B.Min), CVT(B.Max), offset); offset.Scale(0.5f); MeshInst->BaseTransformScaled.TransformPointSlow(offset, offset); #else // scale/translate origin float z = (B.Max.Z + B.Min.Z) / 2; z = (z - Mesh->MeshOrigin.Z) * Mesh->MeshScale.Z; //!! bad formula offset.Set(0, 0, z); #endif offset[2] += Mesh->BoundingSphere.R / 20; // offset a bit up // offset view SetViewOffset(offset); // automatically scale view distance depending on model size float Radius = Mesh->BoundingSphere.R; if (Radius < 10) Radius = 10; SetDistScale(Mesh->MeshScale.X * Radius / 150); }
// function is similar to part of CSkelMeshInstance::SetMesh() static void BuildSkeleton(TArray<CCoords> &Coords, const TArray<RJoint> &Bones, const TArray<AnalogTrack> &Anim) { guard(BuildSkeleton); int numBones = Anim.Num(); Coords.Empty(numBones); Coords.AddZeroed(numBones); for (int i = 0; i < numBones; i++) { const AnalogTrack &A = Anim[i]; const RJoint &B = Bones[i]; CCoords &BC = Coords[i]; // compute reference bone coords CVec3 BP; CQuat BO; // get default pose BP = CVT(A.KeyPos[0]); BO = CVT(A.KeyQuat[0]); if (!i) BO.Conjugate(); BC.origin = BP; BO.ToAxis(BC.axis); // move bone position to global coordinate space if (i) // do not rotate root bone { assert(B.parent >= 0); Coords[B.parent].UnTransformCoords(BC, BC); } } unguard; }
// helper for gradHist, quantize O and M into O0, O1 and M0, M1 (uses sse) void gradQuantize( float *O, float *M, int *O0, int *O1, float *M0, float *M1, int nOrients, int nb, int n, float norm ) { // assumes all *OUTPUT* matrices are 4-byte aligned int i, o0, o1; float o, od, m; __m128i _o0, _o1, *_O0, *_O1; __m128 _o, _o0f, _m, *_M0, *_M1; // define useful constants const float oMult=(float)nOrients/PI; const int oMax=nOrients*nb; const __m128 _norm=SET(norm), _oMult=SET(oMult), _nbf=SET((float)nb); const __m128i _oMax=SET(oMax), _nb=SET(nb); // perform the majority of the work with sse _O0=(__m128i*) O0; _O1=(__m128i*) O1; _M0=(__m128*) M0; _M1=(__m128*) M1; for( i=0; i<=n-4; i+=4 ) { _o=MUL(LDu(O[i]),_oMult); _o0f=CVT(CVT(_o)); _o0=CVT(MUL(_o0f,_nbf)); _o1=ADD(_o0,_nb); _o1=AND(CMPGT(_oMax,_o1),_o1); *_O0++=_o0; *_O1++=_o1; _m=MUL(LDu(M[i]),_norm); *_M1=MUL(SUB(_o,_o0f),_m); *_M0=SUB(_m,*_M1); _M0++; _M1++; } // compute trailing locations without sse for( i; i<n; i++ ) { o=O[i]*oMult; m=M[i]*norm; o0=(int) o; od=o-o0; o0*=nb; o1=o0+nb; if(o1==oMax) o1=0; O0[i]=o0; O1[i]=o1; M1[i]=od*m; M0[i]=m-M1[i]; } }
void UMeshAnimation::ConvertAnims() { guard(UMeshAnimation::ConvertAnims); int i, j; CAnimSet *AnimSet = new CAnimSet(this); ConvertedAnim = AnimSet; // TrackBoneNames int numBones = RefBones.Num(); AnimSet->TrackBoneNames.AddUninitialized(numBones); for (i = 0; i < numBones; i++) AnimSet->TrackBoneNames[i] = RefBones[i].Name; // Sequences int numSeqs = AnimSeqs.Num(); AnimSet->Sequences.AddZeroed(numSeqs); for (i = 0; i < numSeqs; i++) { CAnimSequence &S = AnimSet->Sequences[i]; const FMeshAnimSeq &Src = AnimSeqs[i]; const MotionChunk &M = Moves[i]; // attributes S.Name = Src.Name; S.NumFrames = Src.NumFrames; S.Rate = Src.Rate; // S.Tracks S.Tracks.AddZeroed(numBones); for (j = 0; j < numBones; j++) { CAnimTrack &T = S.Tracks[j]; const AnalogTrack &A = M.AnimTracks[j]; CopyArray(T.KeyPos, CVT(A.KeyPos)); CopyArray(T.KeyQuat, CVT(A.KeyQuat)); CopyArray(T.KeyTime, A.KeyTime); // usually MotionChunk.TrackTime is identical to NumFrames, but some packages exists where // time channel should be adjusted if (M.TrackTime > 0) { float TimeScale = Src.NumFrames / M.TrackTime; for (int k = 0; k < T.KeyTime.Num(); k++) T.KeyTime[k] *= TimeScale; } } } unguard; }
static void cvtcmap(TIFFRGBAImage* img) { uint16* r = img->redcmap; uint16* g = img->greencmap; uint16* b = img->bluecmap; long i; for (i = (1L<<img->bitspersample)-1; i >= 0; i--) { #define CVT(x) ((uint16)(((x) * 255) / ((1L<<16)-1))) r[i] = CVT(r[i]); g[i] = CVT(g[i]); b[i] = CVT(b[i]); #undef CVT } }
static void CheckAndCorrectColormap(TIFF* tif, int n, uint16* r, uint16* g, uint16* b) { int i; for (i = 0; i < n; i++) if (r[i] >= 256 || g[i] >= 256 || b[i] >= 256) return; TIFFWarning(TIFFFileName(tif), "Scaling 8-bit colormap"); #define CVT(x) (((x) * ((1L<<16)-1)) / 255) for (i = 0; i < n; i++) { r[i] = CVT(r[i]); g[i] = CVT(g[i]); b[i] = CVT(b[i]); } #undef CVT }
// helper for gradHist, quantize O and M into O0, O1 and M0, M1 (uses sse) void CPedestrianDetection::gradQuantize(float *O, float *M, int *O0, int *O1, float *M0, float *M1, int nb, int n, float norm, int nOrients, bool full, bool interpolate ) { // assumes all *OUTPUT* matrices are 4-byte aligned int i, o0, o1; float o, od, m; __m128i _o0, _o1, *_O0, *_O1; __m128 _o, _od, _m, *_M0, *_M1; // define useful constants const float oMult=(float)nOrients/(full?2*PI:PI); const int oMax=nOrients*nb; const __m128 _norm=SET(norm), _oMult=SET(oMult), _nbf=SET((float)nb); const __m128i _oMax=SET(oMax), _nb=SET(nb); // perform the majority of the work with sse _O0=(__m128i*) O0; _O1=(__m128i*) O1; _M0=(__m128*) M0; _M1=(__m128*) M1; if( interpolate ) for( i=0; i<=n-4; i+=4 ) { _o=MUL(LDu(O[i]),_oMult); _o0=CVT(_o); _od=SUB(_o,CVT(_o0)); _o0=CVT(MUL(CVT(_o0),_nbf)); _o0=AND(CMPGT(_oMax,_o0),_o0); *_O0++=_o0; _o1=ADD(_o0,_nb); _o1=AND(CMPGT(_oMax,_o1),_o1); *_O1++=_o1; _m=MUL(LDu(M[i]),_norm); *_M1=MUL(_od,_m); *_M0++=SUB(_m,*_M1); _M1++; } else for( i=0; i<=n-4; i+=4 ) { _o=MUL(LDu(O[i]),_oMult); _o0=CVT(ADD(_o,SET(.5f))); _o0=CVT(MUL(CVT(_o0),_nbf)); _o0=AND(CMPGT(_oMax,_o0),_o0); *_O0++=_o0; *_M0++=MUL(LDu(M[i]),_norm); *_M1++=SET(0.f); *_O1++=SET(0); } // compute trailing locations without sse if( interpolate ) for(; i<n; i++ ) { o=O[i]*oMult; o0=(int) o; od=o-o0; o0*=nb; if(o0>=oMax) o0=0; O0[i]=o0; o1=o0+nb; if(o1==oMax) o1=0; O1[i]=o1; m=M[i]*norm; M1[i]=od*m; M0[i]=m-M1[i]; } else for(; i<n; i++ ) { o=O[i]*oMult; o0=(int) (o+.5f); o0*=nb; if(o0>=oMax) o0=0; O0[i]=o0; M0[i]=M[i]*norm; M1[i]=0; O1[i]=0; } }
uint8_t COL_YuvToRgb( uint8_t y,int8_t u,int8_t v,uint8_t *r,uint8_t *g,uint8_t *b) { float rr,bb,gg; float yy=y,uu=u,vv=v; rr= yy+ 1.402*vv; gg= yy+ -0.344*uu+ -0.714*vv; bb= yy+ 1.772*uu ; #define CLIP(x) if(x>255) x=255; else if (x<0) x=0;x=x+0.49; #define CVT(x,y) CLIP(x);*y=(uint8_t)floor(x); CVT(rr,r); CVT(gg,g); CVT(bb,b); return 1; }
/* *--Full format 1 2 3 4 5 6 7 01234567890123456789012345678901234567890123456789012345678901234567890123456789 Sep 1 1990 - start with ' ' Sep 11 11:59 Sep 11 01:59 - start with 0 Sep 11 1:59 - start with ' ' Dec 12 1989 FCv 23 1990 *--Short format: 1 2 3 4 5 6 7 01234567890123456789012345678901234567890123456789012345678901234567890123456789 f 01:07 - time f 01:7 - minutes with one digit F 15:43 f 2002 - only year *--Expanded format: 1 2 3 4 5 6 7 01234567890123456789012345678901234567890123456789012345678901234567890123456789 *2005-06-20 14:22 *2005-07-08 19:21 *2004-10-14 14:14 *2004-10-14 14:14 */ BOOL net_convert_unix_date(LPSTR& datestr, Time_t& decoded) { SYSTEMTIME st; GetSystemTime(&st); st.wMilliseconds = 0; st.wSecond = 0; st.wDayOfWeek = 0; char *bcol = datestr; /* Column begin */ char *ecol; /* Column end */ //Expanded format (DDDD-) if(NET_IS_DIGIT(bcol[0]) && NET_IS_DIGIT(bcol[1]) && NET_IS_DIGIT(bcol[2]) && NET_IS_DIGIT(bcol[3]) && bcol[4] == '-') { #define CVT( nm, start, end ) bcol[end] = 0; \ st.nm = atoi(bcol+start); \ CHECK( (st.nm == MAX_WORD), FALSE ) CVT(wYear, 0, 4) CVT(wMonth, 5, 7) CVT(wDay, 8, 10) CVT(wHour, 11, 13) CVT(wMinute,14, 16) #undef CVT datestr = bcol + 17; return SystemTimeToFileTime(&st, decoded); } //Month+day or short format // (ecol must be set to char after decoded part) if(NET_TO_UPPER(bcol[0]) == 'F' && NET_IS_SPACE(bcol[1])) { //Short format - ignore month and day ecol = bcol + 2; } else { //Month if(NET_IS_DIGIT(bcol[0]) && NET_IS_DIGIT(bcol[1]) && NET_IS_SPACE(bcol[2])) st.wMonth = AtoI(bcol,MAX_WORD); else st.wMonth = NET_MonthNo(datestr); CHECK((st.wMonth == MAX_WORD), FALSE) bcol = SkipSpace(SkipNSpace(bcol)); CHECK((*bcol == 0), FALSE) //Day ecol = SkipNSpace(bcol); if(*ecol != ' ') return FALSE; *ecol = 0; st.wDay = AtoI(bcol,MAX_WORD); *ecol = ' '; CHECK((st.wDay == MAX_WORD), FALSE) } //Year or time ecol = SkipSpace(ecol); bcol = ecol; if(bcol[2] != ':' && bcol[1] != ':') { //Four digits year ecol = SkipDigit(bcol); CHECK((ecol == bcol), FALSE) *ecol = 0; st.wYear = AtoI(bcol,MAX_WORD); ecol++; CHECK((st.wYear == MAX_WORD), FALSE) //Only first three digits of year with cut last digit if(st.wYear > 190 && st.wYear < 300) { st.wYear *= 10; } st.wSecond = 0; st.wMinute = 0; st.wHour = 0; }
bool CxImageTIF::Decode(CxFile * hFile) { //Comment this line if you need more information on errors // TIFFSetErrorHandler(NULL); //<Patrick Hoffmann> //Open file and fill the TIFF structure // m_tif = TIFFOpen(imageFileName,"rb"); TIFF* m_tif = _TIFFOpenEx(hFile, "rb"); uint32 height=0; uint32 width=0; uint16 bitspersample=1; uint16 samplesperpixel=1; uint32 rowsperstrip=(uint32_t)-1; uint16 photometric=0; uint16 compression=1; uint16 orientation=ORIENTATION_TOPLEFT; //<vho> uint16 res_unit; //<Trifon> uint32 x, y; float resolution, offset; bool isRGB; uint8_t *bits; //pointer to source data uint8_t *bits2; //pointer to destination data cx_try { //check if it's a tiff file if (!m_tif) cx_throw("Error encountered while opening TIFF file"); // <Robert Abram> - 12/2002 : get NumFrames directly, instead of looping // info.nNumFrames=0; // while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++; info.nNumFrames = TIFFNumberOfDirectories(m_tif); if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame)) cx_throw("Error: page not present in TIFF file"); //get image info TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation); if (info.nEscape == -1) { // Return output dimensions only head.biWidth = width; head.biHeight = height; info.dwType = CXIMAGE_FORMAT_TIF; cx_throw("output dimensions returned"); } TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit); if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetXDPI((int32_t)resolution); } if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetYDPI((int32_t)resolution); } if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (int32_t)offset; if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (int32_t)offset; head.biClrUsed=0; info.nBkgndIndex =-1; if (rowsperstrip>height){ rowsperstrip=height; TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); } isRGB = /*(bitspersample >= 8) && (VK: it is possible so for RGB to have < 8 bpp!)*/ (photometric == PHOTOMETRIC_RGB) || (photometric == PHOTOMETRIC_YCBCR) || (photometric == PHOTOMETRIC_SEPARATED) || (photometric == PHOTOMETRIC_LOGL) || (photometric == PHOTOMETRIC_LOGLUV); if (isRGB){ head.biBitCount=24; }else{ if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)||(photometric==PHOTOMETRIC_PALETTE)){ if (bitspersample == 1){ head.biBitCount=1; //B&W image head.biClrUsed =2; } else if (bitspersample == 4) { head.biBitCount=4; //16 colors gray scale head.biClrUsed =16; } else { head.biBitCount=8; //gray scale head.biClrUsed =256; } } else if (bitspersample == 4) { head.biBitCount=4; // 16 colors head.biClrUsed=16; } else { head.biBitCount=8; //256 colors head.biClrUsed=256; } if ((bitspersample > 8) && (photometric==PHOTOMETRIC_PALETTE)) // + VK + (BIG palette! => convert to RGB) { head.biBitCount=24; head.biClrUsed =0; } } if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation if (!pDib) cx_throw("CxImageTIF can't create image"); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha #endif //CXIMAGE_SUPPORT_ALPHA TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); SetCodecOption(compression); // <DPR> save original compression type if (isRGB) { // Read the whole image into one big RGBA buffer using // the traditional TIFFReadRGBAImage() API that we trust. uint32* raster; // retrieve RGBA image uint32 *row; raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); if (raster == NULL) cx_throw("No space for raster buffer"); // Read the image in one chunk into an RGBA array if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { _TIFFfree(raster); cx_throw("Corrupted TIFF file!"); } // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB row = &raster[0]; bits2 = info.pImage; for (y = 0; y < height; y++) { if (info.nEscape){ // <vho> - cancel decoding _TIFFfree(raster); cx_throw("Cancelled"); } bits = bits2; for (x = 0; x < width; x++) { *bits++ = (uint8_t)TIFFGetB(row[x]); *bits++ = (uint8_t)TIFFGetG(row[x]); *bits++ = (uint8_t)TIFFGetR(row[x]); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(x,y,(uint8_t)TIFFGetA(row[x])); #endif //CXIMAGE_SUPPORT_ALPHA } row += width; bits2 += info.dwEffWidth; } _TIFFfree(raster); } else { int32_t BIG_palette = (bitspersample > 8) && // + VK (photometric==PHOTOMETRIC_PALETTE); if (BIG_palette && (bitspersample > 24)) // + VK cx_throw("Too big palette to handle"); // + VK RGBQuad *pal; pal=(RGBQuad*)calloc(BIG_palette ? 1<<bitspersample : 256,sizeof(RGBQuad)); // ! VK: it coasts nothing but more correct to use 256 as temp palette storage // ! VK: but for case of BIG palette it just copied if (pal==NULL) cx_throw("Unable to allocate TIFF palette"); int32_t bpp = bitspersample <= 8 ? bitspersample : 8; // + VK (to use instead of bitspersample for case of > 8) // set up the colormap based on photometric switch(photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: if (bitspersample == 1) { // Monochrome image if (photometric == PHOTOMETRIC_MINISBLACK) { pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; } } else { // need to build the scale for greyscale images if (photometric == PHOTOMETRIC_MINISBLACK) { for (int32_t i=0; i<(1<<bpp); i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (uint8_t)(i*(255/((1<<bpp)-1))); } } else { for (int32_t i=0; i<(1<<bpp); i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (uint8_t)(255-i*(255/((1<<bpp)-1))); } } } break; case PHOTOMETRIC_PALETTE: // color map indexed uint16 *red; uint16 *green; uint16 *blue; TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? bool Palette16Bits = /*false*/ BIG_palette; if (!BIG_palette) { int32_t n= 1<<bpp; while (n-- > 0) { if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { Palette16Bits=true; break; } } } // load the palette in the DIB for (int32_t i = (1 << ( BIG_palette ? bitspersample : bpp )) - 1; i >= 0; i--) { if (Palette16Bits) { pal[i].rgbRed =(uint8_t) CVT(red[i]); pal[i].rgbGreen = (uint8_t) CVT(green[i]); pal[i].rgbBlue = (uint8_t) CVT(blue[i]); } else { pal[i].rgbRed = (uint8_t) red[i]; pal[i].rgbGreen = (uint8_t) green[i]; pal[i].rgbBlue = (uint8_t) blue[i]; } } break; } if (!BIG_palette) { // + VK (BIG palette is stored until image is ready) SetPalette(pal,/*head.biClrUsed*/ 1<<bpp); //palette assign // * VK free(pal); pal = NULL; } // read the tiff lines and save them in the DIB uint32 nrow; uint32 ys; int32_t line = CalculateLine(width, bitspersample * samplesperpixel); int32_t bitsize = TIFFStripSize(m_tif); //verify bitsize: could be wrong if StripByteCounts is missing. if (bitsize>(int32_t)(head.biSizeImage*samplesperpixel)) bitsize = head.biSizeImage*samplesperpixel; if (bitsize<(int32_t)(info.dwEffWidth*rowsperstrip)) bitsize = info.dwEffWidth*rowsperstrip; if ((bitspersample > 8) && (bitspersample != 16)) // + VK (for bitspersample == 9..15,17..32..64 bitsize *= (bitspersample + 7)/8; int32_t tiled_image = TIFFIsTiled(m_tif); uint32 tw=0, tl=0; uint8_t* tilebuf=NULL; if (tiled_image){ TIFFGetField(m_tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(m_tif, TIFFTAG_TILELENGTH, &tl); rowsperstrip = tl; bitsize = TIFFTileSize(m_tif) * (int32_t)(1+width/tw); tilebuf = (uint8_t*)malloc(TIFFTileSize(m_tif)); } bits = (uint8_t*)malloc(bitspersample==16? bitsize*2 : bitsize); // * VK uint8_t * bits16 = NULL; // + VK int32_t line16 = 0; // + VK if (!tiled_image && bitspersample==16) { // + VK + line16 = line; line = CalculateLine(width, 8 * samplesperpixel); bits16 = bits; bits = (uint8_t*)malloc(bitsize); } if (bits==NULL){ if (bits16) free(bits16); // + VK if (pal) free(pal); // + VK if (tilebuf)free(tilebuf); // + VK cx_throw("CxImageTIF can't allocate memory"); } #ifdef FIX_16BPP_DARKIMG // + VK: for each line, store shift count bits used to fix it uint8_t* row_shifts = NULL; if (bits16) row_shifts = (uint8_t*)malloc(height); #endif for (ys = 0; ys < height; ys += rowsperstrip) { if (info.nEscape){ // <vho> - cancel decoding free(bits); cx_throw("Cancelled"); } nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); if (tiled_image){ uint32 imagew = TIFFScanlineSize(m_tif); uint32 tilew = TIFFTileRowSize(m_tif); int32_t iskew = imagew - tilew; uint8* bufp = (uint8*) bits; uint32 colb = 0; for (uint32 col = 0; col < width; col += tw) { if (TIFFReadTile(m_tif, tilebuf, col, ys, 0, 0) < 0){ free(tilebuf); free(bits); cx_throw("Corrupted tiled TIFF file!"); } if (colb + tw > imagew) { uint32 owidth = imagew - colb; uint32 oskew = tilew - owidth; TileToStrip(bufp + colb, tilebuf, nrow, owidth, oskew + iskew, oskew ); } else { TileToStrip(bufp + colb, tilebuf, nrow, tilew, iskew, 0); } colb += tilew; } } else { if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), (bits16? bits16 : bits), nrow * (bits16 ? line16 : line)) == -1) { // * VK #ifdef NOT_IGNORE_CORRUPTED free(bits); if (bits16) free(bits16); // + VK cx_throw("Corrupted TIFF file!"); #else break; #endif } } for (y = 0; y < nrow; y++) { int32_t offset=(nrow-y-1)*line; if ((bitspersample==16) && !BIG_palette) { // * VK int32_t offset16 = (nrow-y-1)*line16; // + VK if (bits16) { // + VK + #ifdef FIX_16BPP_DARKIMG int32_t the_shift; uint8_t hi_byte, hi_max=0; uint32_t xi; for (xi=0;xi<(uint32)line;xi++) { hi_byte = bits16[xi*2+offset16+1]; if(hi_byte>hi_max) hi_max = hi_byte; } the_shift = (hi_max == 0) ? 8 : 0; if (!the_shift) while( ! (hi_max & 0x80) ) { the_shift++; hi_max <<= 1; } row_shifts[height-ys-nrow+y] = the_shift; the_shift = 8 - the_shift; for (xi=0;xi<(uint32)line;xi++) bits[xi+offset]= ((bits16[xi*2+offset16+1]<<8) | bits16[xi*2+offset16]) >> the_shift; #else for (uint32_t xi=0;xi<(uint32)line;xi++) bits[xi+offset]=bits16[xi*2+offset16+1]; #endif } else { for (uint32_t xi=0;xi<width;xi++) bits[xi+offset]=bits[xi*2+offset+1]; } } if (samplesperpixel==1) { if (BIG_palette) if (bits16) { int32_t offset16 = (nrow-y-1)*line16; // + VK MoveBitsPal( info.pImage + info.dwEffWidth * (height-ys-nrow+y), bits16 + offset16, width, bitspersample, pal ); } else MoveBitsPal( info.pImage + info.dwEffWidth * (height-ys-nrow+y), bits + offset, width, bitspersample, pal ); else if ((bitspersample == head.biBitCount) || (bitspersample == 16)) //simple 8bpp, 4bpp image or 16bpp memcpy(info.pImage+info.dwEffWidth*(height-ys-nrow+y),bits+offset,min((unsigned)line, info.dwEffWidth)); else MoveBits( info.pImage + info.dwEffWidth * (height-ys-nrow+y), bits + offset, width, bitspersample ); } else if (samplesperpixel==2) { //8bpp image with alpha layer int32_t xi=0; int32_t ii=0; int32_t yi=height-ys-nrow+y; #if CXIMAGE_SUPPORT_ALPHA if (!pAlpha) AlphaCreate(); // + VK #endif //CXIMAGE_SUPPORT_ALPHA while (ii<line){ SetPixelIndex(xi,yi,bits[ii+offset]); #if CXIMAGE_SUPPORT_ALPHA AlphaSet(xi,yi,bits[ii+offset+1]); #endif //CXIMAGE_SUPPORT_ALPHA ii+=2; xi++; if (xi>=(int32_t)width){ yi--; xi=0; } } } else { //photometric==PHOTOMETRIC_CIELAB if (head.biBitCount!=24){ //fix image Create(width,height,24,CXIMAGE_FORMAT_TIF); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); #endif //CXIMAGE_SUPPORT_ALPHA } int32_t xi=0; uint32 ii=0; int32_t yi=height-ys-nrow+y; RGBQuad c; int32_t l,a,b,bitsoffset; double p,cx,cy,cz,cr,cg,cb; while (ii</*line*/width){ // * VK bitsoffset = ii*samplesperpixel+offset; l=bits[bitsoffset]; a=bits[bitsoffset+1]; b=bits[bitsoffset+2]; if (a>127) a-=256; if (b>127) b-=256; // lab to xyz p = (l/2.55 + 16) / 116.0; cx = pow( p + a * 0.002, 3); cy = pow( p, 3); cz = pow( p - b * 0.005, 3); // white point cx*=0.95047; //cy*=1.000; cz*=1.0883; // xyz to rgb cr = 3.240479 * cx - 1.537150 * cy - 0.498535 * cz; cg = -0.969256 * cx + 1.875992 * cy + 0.041556 * cz; cb = 0.055648 * cx - 0.204043 * cy + 1.057311 * cz; if ( cr > 0.00304 ) cr = 1.055 * pow(cr,0.41667) - 0.055; else cr = 12.92 * cr; if ( cg > 0.00304 ) cg = 1.055 * pow(cg,0.41667) - 0.055; else cg = 12.92 * cg; if ( cb > 0.00304 ) cb = 1.055 * pow(cb,0.41667) - 0.055; else cb = 12.92 * cb; c.rgbRed =(uint8_t)max(0,min(255,(int32_t)(cr*255))); c.rgbGreen=(uint8_t)max(0,min(255,(int32_t)(cg*255))); c.rgbBlue =(uint8_t)max(0,min(255,(int32_t)(cb*255))); SetPixelColor(xi,yi,c); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(xi,yi,bits[bitsoffset+3]); #endif //CXIMAGE_SUPPORT_ALPHA ii++; xi++; if (xi>=(int32_t)width){ yi--; xi=0; } } } } } free(bits); if (bits16) free(bits16); #ifdef FIX_16BPP_DARKIMG if (row_shifts && (samplesperpixel == 1) && (bitspersample==16) && !BIG_palette) { // 1. calculate maximum necessary shift int32_t min_row_shift = 8; for( y=0; y<height; y++ ) { if (min_row_shift > row_shifts[y]) min_row_shift = row_shifts[y]; } // 2. for rows having less shift value, correct such rows: for( y=0; y<height; y++ ) { if (min_row_shift < row_shifts[y]) { int32_t need_shift = row_shifts[y] - min_row_shift; uint8_t* data = info.pImage + info.dwEffWidth * y; for( x=0; x<width; x++, data++ ) *data >>= need_shift; } }
void PLTIFFDecoder::doLoColor (TIFF * tif, PLBmpBase * pBmp) { uint16 BitsPerSample; uint16 SamplePerPixel; int32 LineSize; int16 PhotometricInterpretation; int row; PLBYTE *pBits; TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample); TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &SamplePerPixel); TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation); if (PhotometricInterpretation!=PHOTOMETRIC_MINISWHITE && PhotometricInterpretation!=PHOTOMETRIC_MINISBLACK && PhotometricInterpretation!=PHOTOMETRIC_PALETTE) { PhotometricInterpretation = PHOTOMETRIC_MINISWHITE; Trace(2,"unexpected PhotometricInterpretation, default to PHOTOMETRIC_MINISWHITE"); } LineSize = TIFFScanlineSize(tif); //Number of bytes in one line PLPixel32 pPal[256]; pBits = new PLBYTE [LineSize]; // enough for 16-bits per pixel if (pBits == NULL) raiseError (PL_ERRNO_MEMORY, "Out of memory allocating TIFF buffer."); // phase one: build color map if (BitsPerSample < 16) { if /* monochrome (=bitonal) or grayscale */ (PhotometricInterpretation == PHOTOMETRIC_MINISWHITE || PhotometricInterpretation == PHOTOMETRIC_MINISBLACK) { int numColors = 1 << BitsPerSample; PLBYTE step = static_cast<PLBYTE>(255 / (numColors-1)); PLBYTE *pb = (PLBYTE *) (pPal); int offset = sizeof(PLPixel32); if (PhotometricInterpretation == PHOTOMETRIC_MINISWHITE) { pb += (numColors-1) * sizeof(PLPixel32); offset = -offset; } // warning: the following ignores possible halftone hints for (int i = 0; i < numColors; ++i, pb += offset) { pb[PL_RGBA_RED] = pb[PL_RGBA_GREEN] = pb[PL_RGBA_BLUE] = static_cast<PLBYTE>(i * step); pb[PL_RGBA_ALPHA] = 255; } } //PhotometricInterpretation = 2 image is RGB //PhotometricInterpretation = 3 image has a color palette else if (PhotometricInterpretation == PHOTOMETRIC_PALETTE) { uint16* red; uint16* green; uint16* blue; int16 Palette16Bits; // we get pointers to libtiff-owned colormaps TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue); //Is the palette 16 or 8 bits ? Palette16Bits = checkcmap(1<<BitsPerSample, red, green, blue) == 16; //load the palette in the DIB for (int i = 0; i < 1<<BitsPerSample; ++i) { PLBYTE *pb = (PLBYTE *) ((pPal)+i); pb[PL_RGBA_RED ] = (PLBYTE) (Palette16Bits ? CVT( red[i]) : red[i]); pb[PL_RGBA_GREEN] = (PLBYTE) (Palette16Bits ? CVT(green[i]) : green[i]); pb[PL_RGBA_BLUE ] = (PLBYTE) (Palette16Bits ? CVT( blue[i]) : blue[i]); pb[PL_RGBA_ALPHA] = 255; } } else Trace( 2, "unexpected PhotometricInterpretation in PLTIFFDecoder::DoLoColor()" ); } // phase two: read image itself //generally, TIFF images are ordered from upper-left to bottom-right // we implicitly assume PLANARCONFIG_CONTIG PLBYTE **pLineArray = pBmp->GetLineArray(); if (BitsPerSample > 16) Trace( 2, "unexpected bit-depth in PLTIFFDecoder::DoLoColor()" ); else for ( row = 0; row < GetHeight(); ++row ) { uint16 x; int status = TIFFReadScanline( tif, pBits, row, 0 ); if (status == -1 && row < GetHeight() / 3) { delete [] pBits; // we should maybe free the BMP memory as well... raiseError (PL_ERRINTERNAL, m_szLastErr); } /* if (BitsPerSample == 1) // go ahead, waste space ;-) for (x=0; x < imageWidth; ++x) pLineArray[row][x] = pBits[x / 8] & (128 >> (x & 7)) ? 1 : 0; else */ if (BitsPerSample == 4) { for (x=0; x < GetWidth() / 2; ++x) { pLineArray[row][2*x ] = (pBits[x] & 0xf0) >> 4; pLineArray[row][2*x+1] = (pBits[x] & 0x0f); } // odd number of pixels if (GetWidth() & 1) pLineArray[row][GetWidth()-1] = (pBits[x] & 0xf0) >> 4; } else if (BitsPerSample == 16) { PLASSERT (SamplePerPixel == 1); // can't do 16-bit with alpha yet PLPixel16 **pLineArray16 = pBmp->GetLineArray16(); memcpy( pLineArray16[row], pBits, LineSize ); } else //if (BitsPerSample == 8 || BitsPerSample == 1) if (SamplePerPixel == 1) memcpy( pLineArray[row], pBits, LineSize ); else { // We've got an 8 bit image with an alpha channel. // Ignore the alpha channel. PLASSERT (BitsPerSample == 8); for (x=0; x < GetWidth(); ++x) pLineArray[row][x] = pBits[x*2]; } }
void PSDataPalette(FILE* fd, TIFF* tif, uint32 w, uint32 h) { uint16 *rmap, *gmap, *bmap; uint32 row; int breaklen = MAXLINE, cc, nc; unsigned char *tf_buf; unsigned char *cp, c; (void) w; if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) { TIFFError(filename, "Palette image w/o \"Colormap\" tag"); return; } switch (bitspersample) { case 8: case 4: case 2: case 1: break; default: TIFFError(filename, "Depth %d not supported", bitspersample); return; } nc = 3 * (8 / bitspersample); tf_buf = (unsigned char *) _TIFFmalloc(tf_bytesperrow); if (tf_buf == NULL) { TIFFError(filename, "No space for scanline buffer"); return; } if (checkcmap(tif, 1<<bitspersample, rmap, gmap, bmap) == 16) { int i; #define CVT(x) (((x) * 255) / ((1U<<16)-1)) for (i = (1<<bitspersample)-1; i >= 0; i--) { rmap[i] = CVT(rmap[i]); gmap[i] = CVT(gmap[i]); bmap[i] = CVT(bmap[i]); } #undef CVT } for (row = 0; row < h; row++) { if (TIFFReadScanline(tif, tf_buf, row, 0) < 0) break; for (cp = tf_buf, cc = 0; cc < tf_bytesperrow; cc++) { DOBREAK(breaklen, nc, fd); switch (bitspersample) { case 8: c = *cp++; PUTRGBHEX(c, fd); break; case 4: c = *cp++; PUTRGBHEX(c&0xf, fd); c >>= 4; PUTRGBHEX(c, fd); break; case 2: c = *cp++; PUTRGBHEX(c&0x3, fd); c >>= 2; PUTRGBHEX(c&0x3, fd); c >>= 2; PUTRGBHEX(c&0x3, fd); c >>= 2; PUTRGBHEX(c, fd); break; case 1: c = *cp++; PUTRGBHEX(c&0x1, fd); c >>= 1; PUTRGBHEX(c&0x1, fd); c >>= 1; PUTRGBHEX(c&0x1, fd); c >>= 1; PUTRGBHEX(c&0x1, fd); c >>= 1; PUTRGBHEX(c&0x1, fd); c >>= 1; PUTRGBHEX(c&0x1, fd); c >>= 1; PUTRGBHEX(c&0x1, fd); c >>= 1; PUTRGBHEX(c, fd); break; } } } _TIFFfree((char *) tf_buf); }
bool CxImageTIF::Decode(CxFile * hFile) { //Comment this line if you need more information on errors // TIFFSetErrorHandler(NULL); //<Patrick Hoffmann> //Open file and fill the TIFF structure // m_tif = TIFFOpen(imageFileName,"rb"); TIFF* m_tif = _TIFFOpenEx(hFile, "rb"); uint32 height=0; uint32 width=0; uint16 bitspersample=1; uint16 samplesperpixel=1; uint32 rowsperstrip=(DWORD)-1; uint16 photometric=0; uint16 compression=1; uint16 orientation=ORIENTATION_TOPLEFT; //<vho> uint16 res_unit; //<Trifon> uint32 x, y; float resolution, offset; BOOL isRGB; BYTE *bits; //pointer to source data BYTE *bits2; //pointer to destination data try{ //check if it's a tiff file if (!m_tif) throw "Error encountered while opening TIFF file"; // <Robert Abram> - 12/2002 : get NumFrames directly, instead of looping // info.nNumFrames=0; // while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++; info.nNumFrames = TIFFNumberOfDirectories(m_tif); if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame)) throw "Error: page not present in TIFF file"; //get image info TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation); if (info.nEscape == -1) { // Return output dimensions only head.biWidth = width; head.biHeight = height; throw "output dimensions returned"; } TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit); if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetXDPI((long)resolution); } if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetYDPI((long)resolution); } if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (long)offset; if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (long)offset; head.biClrUsed=0; info.nBkgndIndex =-1; if (rowsperstrip>height){ rowsperstrip=height; TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); } isRGB = (bitspersample >= 8) && (photometric == PHOTOMETRIC_RGB) || (photometric == PHOTOMETRIC_YCBCR) || (photometric == PHOTOMETRIC_SEPARATED) || (photometric == PHOTOMETRIC_LOGL) || (photometric == PHOTOMETRIC_LOGLUV); if (isRGB){ head.biBitCount=24; }else{ if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)){ if (bitspersample == 1){ head.biBitCount=1; //B&W image head.biClrUsed =2; } else if (bitspersample == 4) { head.biBitCount=4; //16 colors gray scale head.biClrUsed =16; } else { head.biBitCount=8; //gray scale head.biClrUsed =256; } } else if (bitspersample == 4) { head.biBitCount=4; // 16 colors head.biClrUsed=16; } else { head.biBitCount=8; //256 colors head.biClrUsed=256; } } if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation if (!pDib) throw "CxImageTIF can't create image"; #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha #endif //CXIMAGE_SUPPORT_ALPHA TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); SetCodecOption(compression); // <DPR> save original compression type if (isRGB) { // Read the whole image into one big RGBA buffer using // the traditional TIFFReadRGBAImage() API that we trust. uint32* raster; // retrieve RGBA image uint32 *row; raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); if (raster == NULL) throw "No space for raster buffer"; // Read the image in one chunk into an RGBA array if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { _TIFFfree(raster); throw "Corrupted TIFF file!"; } // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB row = &raster[0]; bits2 = info.pImage; for (y = 0; y < height; y++) { if (info.nEscape){ // <vho> - cancel decoding _TIFFfree(raster); throw "Cancelled"; } bits = bits2; for (x = 0; x < width; x++) { *bits++ = (BYTE)TIFFGetB(row[x]); *bits++ = (BYTE)TIFFGetG(row[x]); *bits++ = (BYTE)TIFFGetR(row[x]); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(x,y,(BYTE)TIFFGetA(row[x])); #endif //CXIMAGE_SUPPORT_ALPHA } row += width; bits2 += info.dwEffWidth; } _TIFFfree(raster); } else { RGBQUAD *pal; pal=(RGBQUAD*)calloc(256,sizeof(RGBQUAD)); if (pal==NULL) throw "Unable to allocate TIFF palette"; // set up the colormap based on photometric switch(photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: if (bitspersample == 1) { // Monochrome image if (photometric == PHOTOMETRIC_MINISBLACK) { pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; } } else { // need to build the scale for greyscale images if (photometric == PHOTOMETRIC_MINISBLACK) { for (DWORD i=0; i<head.biClrUsed; i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(i*(255/(head.biClrUsed-1))); } } else { for (DWORD i=0; i<head.biClrUsed; i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(255-i*(255/(head.biClrUsed-1))); } } } break; case PHOTOMETRIC_PALETTE: // color map indexed uint16 *red; uint16 *green; uint16 *blue; TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? BOOL Palette16Bits = FALSE; int n=1<<bitspersample; while (n-- > 0) { if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { Palette16Bits=TRUE; break; } } // load the palette in the DIB for (int i = (1 << bitspersample) - 1; i >= 0; i--) { if (Palette16Bits) { pal[i].rgbRed =(BYTE) CVT(red[i]); pal[i].rgbGreen = (BYTE) CVT(green[i]); pal[i].rgbBlue = (BYTE) CVT(blue[i]); } else { pal[i].rgbRed = (BYTE) red[i]; pal[i].rgbGreen = (BYTE) green[i]; pal[i].rgbBlue = (BYTE) blue[i]; } } break; } SetPalette(pal,head.biClrUsed); //palette assign free(pal); // read the tiff lines and save them in the DIB uint32 nrow; uint32 ys; int line = CalculateLine(width, bitspersample * samplesperpixel); long bitsize= TIFFStripSize(m_tif); //verify bitsize: could be wrong if StripByteCounts is missing. if (bitsize>(long)(head.biSizeImage*samplesperpixel)) bitsize=head.biSizeImage*samplesperpixel; int tiled_image = TIFFIsTiled(m_tif); uint32 tw, tl; BYTE* tilebuf; if (tiled_image){ TIFFGetField(m_tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(m_tif, TIFFTAG_TILELENGTH, &tl); rowsperstrip = tl; bitsize = TIFFTileSize(m_tif) * (int)(1+width/tw); tilebuf = (BYTE*)malloc(TIFFTileSize(m_tif)); } bits = (BYTE*)malloc(bitsize); if (bits==NULL){ throw "CxImageTIF can't allocate memory"; } for (ys = 0; ys < height; ys += rowsperstrip) { if (info.nEscape){ // <vho> - cancel decoding free(bits); throw "Cancelled"; } nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); if (tiled_image){ uint32 imagew = TIFFScanlineSize(m_tif); uint32 tilew = TIFFTileRowSize(m_tif); int iskew = imagew - tilew; uint8* bufp = (uint8*) bits; uint32 colb = 0; for (uint32 col = 0; col < width; col += tw) { if (TIFFReadTile(m_tif, tilebuf, col, ys, 0, 0) < 0){ free(tilebuf); free(bits); throw "Corrupted tiled TIFF file!"; } if (colb + tw > imagew) { uint32 owidth = imagew - colb; uint32 oskew = tilew - owidth; TileToStrip(bufp + colb, tilebuf, nrow, owidth, oskew + iskew, oskew ); } else { TileToStrip(bufp + colb, tilebuf, nrow, tilew, iskew, 0); } colb += tilew; } } else { if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), bits, nrow * line) == -1) { free(bits); throw "Corrupted TIFF file!"; } } for (y = 0; y < nrow; y++) { long offset=(nrow-y-1)*line; if (bitspersample==16) for (DWORD xi=0;xi<width;xi++) bits[xi+offset]=bits[xi*2+offset+1]; if (samplesperpixel==1) { //simple 8bpp image memcpy(info.pImage+info.dwEffWidth*(height-ys-nrow+y),bits+offset,info.dwEffWidth); } else if (samplesperpixel==2) { //8bpp image with alpha layer int xi=0; int ii=0; int yi=height-ys-nrow+y; while (ii<line){ SetPixelIndex(xi,yi,bits[ii+offset]); #if CXIMAGE_SUPPORT_ALPHA AlphaSet(xi,yi,bits[ii+offset+1]); #endif //CXIMAGE_SUPPORT_ALPHA ii+=2; xi++; if (xi>=(int)width){ yi--; xi=0; } } } else { //photometric==PHOTOMETRIC_CIELAB if (head.biBitCount!=24){ //fix image Create(width,height,24,CXIMAGE_FORMAT_TIF); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); #endif //CXIMAGE_SUPPORT_ALPHA } int xi=0; int ii=0; int yi=height-ys-nrow+y; RGBQUAD c; int l,a,b,bitsoffset; double p,cx,cy,cz,cr,cg,cb; while (ii<line){ bitsoffset = ii*samplesperpixel+offset; l=bits[bitsoffset]; a=bits[bitsoffset+1]; b=bits[bitsoffset+2]; if (a>127) a-=256; if (b>127) b-=256; // lab to xyz p = (l/2.55 + 16) / 116.0; cx = pow( p + a * 0.002, 3); cy = pow( p, 3); cz = pow( p - b * 0.005, 3); // white point cx*=0.95047; //cy*=1.000; cz*=1.0883; // xyz to rgb cr = 3.240479 * cx - 1.537150 * cy - 0.498535 * cz; cg = -0.969256 * cx + 1.875992 * cy + 0.041556 * cz; cb = 0.055648 * cx - 0.204043 * cy + 1.057311 * cz; if ( cr > 0.00304 ) cr = 1.055 * pow(cr,0.41667) - 0.055; else cr = 12.92 * cr; if ( cg > 0.00304 ) cg = 1.055 * pow(cg,0.41667) - 0.055; else cg = 12.92 * cg; if ( cb > 0.00304 ) cb = 1.055 * pow(cb,0.41667) - 0.055; else cb = 12.92 * cb; c.rgbRed =(BYTE)max(0,min(255,(int)(cr*255))); c.rgbGreen=(BYTE)max(0,min(255,(int)(cg*255))); c.rgbBlue =(BYTE)max(0,min(255,(int)(cb*255))); SetPixelColor(xi,yi,c); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(xi,yi,bits[bitsoffset+3]); #endif //CXIMAGE_SUPPORT_ALPHA ii++; xi++; if (xi>=(int)width){ yi--; xi=0; } } } } } free(bits); if (tiled_image) free(tilebuf); switch(orientation){ case ORIENTATION_TOPRIGHT: /* row 0 top, col 0 rhs */ Mirror(); break; case ORIENTATION_BOTRIGHT: /* row 0 bottom, col 0 rhs */ Flip(); Mirror(); break; case ORIENTATION_BOTLEFT: /* row 0 bottom, col 0 lhs */ Flip(); break; case ORIENTATION_LEFTTOP: /* row 0 lhs, col 0 top */ RotateRight(); Mirror(); break; case ORIENTATION_RIGHTTOP: /* row 0 rhs, col 0 top */ RotateLeft(); break; case ORIENTATION_RIGHTBOT: /* row 0 rhs, col 0 bottom */ RotateLeft(); Mirror(); break; case ORIENTATION_LEFTBOT: /* row 0 lhs, col 0 bottom */ RotateRight(); break; } } } catch (char *message) { strncpy(info.szLastError,message,255); if (m_tif) TIFFClose(m_tif); if (info.nEscape==-1) return true; return false; } TIFFClose(m_tif); return true; }
void CVertMeshInstance::SetMesh(const UVertMesh *Mesh) { pMesh = Mesh; SetAxis(Mesh->RotOrigin, BaseTransform.axis); BaseTransform.origin[0] = Mesh->MeshOrigin.X * Mesh->MeshScale.X; BaseTransform.origin[1] = Mesh->MeshOrigin.Y * Mesh->MeshScale.Y; BaseTransform.origin[2] = Mesh->MeshOrigin.Z * Mesh->MeshScale.Z; BaseTransformScaled.axis = BaseTransform.axis; CVec3 tmp; tmp[0] = 1.0f / Mesh->MeshScale.X; tmp[1] = 1.0f / Mesh->MeshScale.Y; tmp[2] = 1.0f / Mesh->MeshScale.Z; BaseTransformScaled.axis.PrescaleSource(tmp); BaseTransformScaled.origin = CVT(Mesh->MeshOrigin); FreeRenderBuffers(); if (!pMesh->Faces.Num()) return; // prepare vertex and index buffers, build sections Verts = new CVec3[pMesh->Wedges.Num()]; Normals = new CVec3[pMesh->Wedges.Num()]; Indices = new word[pMesh->Faces.Num() * 3]; const FMeshFace *F = &pMesh->Faces[0]; word *pIndex = Indices; int PrevMaterial = -2; CMeshSection *Sec = NULL; for (int i = 0; i < pMesh->Faces.Num(); i++, F++) { if (F->MaterialIndex != PrevMaterial) { // get material parameters int PolyFlags = 0; int TexIndex = 1000000; if (F->MaterialIndex < pMesh->Materials.Num()) { const FMeshMaterial &M = pMesh->Materials[F->MaterialIndex]; TexIndex = M.TextureIndex; PolyFlags = M.PolyFlags; } // possible situation: Textures array is empty (mesh textured by script) UUnrealMaterial *Mat = (TexIndex < pMesh->Textures.Num()) ? MATERIAL_CAST(pMesh->Textures[TexIndex]) : NULL; // create new section Sec = new (Sections) CMeshSection; Sec->FirstIndex = pIndex - Indices; Sec->NumFaces = 0; Sec->Material = UMaterialWithPolyFlags::Create(Mat, PolyFlags); PrevMaterial = F->MaterialIndex; } // store indices // note: skeletal mesh and vertex mesh has opposite triangle vertex order *pIndex++ = F->iWedge[0]; *pIndex++ = F->iWedge[2]; *pIndex++ = F->iWedge[1]; Sec->NumFaces++; } }
void USkeletalMesh::ConvertMesh() { guard(USkeletalMesh::ConvertMesh); CSkeletalMesh *Mesh = new CSkeletalMesh(this); ConvertedMesh = Mesh; Mesh->BoundingBox = BoundingBox; Mesh->BoundingSphere = BoundingSphere; Mesh->RotOrigin = RotOrigin; Mesh->MeshScale = CVT(MeshScale); Mesh->MeshOrigin = CVT(MeshOrigin); Mesh->Lods.Empty(LODModels.Num()); #if DEBUG_SKELMESH appPrintf(" Base : Points[%d] Wedges[%d] Influences[%d] Faces[%d]\n", Points.Num(), Wedges.Num(), VertInfluences.Num(), Triangles.Num() ); #endif // some games has troubles with LOD models ... #if TRIBES3 if (GetGame() == GAME_Tribes3) goto base_mesh; #endif #if SWRC if (GetGame() == GAME_RepCommando) goto base_mesh; #endif if (!LODModels.Num()) { base_mesh: guard(ConvertBaseMesh); // create CSkelMeshLod from base mesh CSkelMeshLod *Lod = new (Mesh->Lods) CSkelMeshLod; Lod->NumTexCoords = 1; Lod->HasNormals = false; Lod->HasTangents = false; if (Points.Num() && Wedges.Num() && VertInfluences.Num()) { InitSections(*Lod); ConvertWedges(*Lod, Points, Wedges, VertInfluences); BuildIndices(*Lod); } else { appPrintf("ERROR: bad base mesh\n"); } goto skeleton; unguard; } // convert LODs for (int lod = 0; lod < LODModels.Num(); lod++) { guard(ConvertLod); const FStaticLODModel &SrcLod = LODModels[lod]; #if DEBUG_SKELMESH appPrintf(" Lod %d: Points[%d] Wedges[%d] Influences[%d] Faces[%d] Rigid(Indices[%d] Verts[%d]) Smooth(Indices[%d] Verts[%d] Stream[%d])\n", lod, SrcLod.Points.Num(), SrcLod.Wedges.Num(), SrcLod.VertInfluences.Num(), SrcLod.Faces.Num(), SrcLod.RigidIndices.Indices.Num(), SrcLod.VertexStream.Verts.Num(), SrcLod.SmoothIndices.Indices.Num(), SrcLod.SkinPoints.Num(), SrcLod.SkinningData.Num() ); #endif // if (SrcLod.Faces.Num() == 0 && SrcLod.SmoothSections.Num() > 0) // continue; CSkelMeshLod *Lod = new (Mesh->Lods) CSkelMeshLod; Lod->NumTexCoords = 1; Lod->HasNormals = false; Lod->HasTangents = false; if (IsCorrectLOD(SrcLod)) { InitSections(*Lod); ConvertWedges(*Lod, SrcLod.Points, SrcLod.Wedges, SrcLod.VertInfluences); BuildIndicesForLod(*Lod, SrcLod); } else { appPrintf("WARNING: bad LOD#%d mesh, switching to base\n", lod); if (lod == 0) { Mesh->Lods.Empty(); goto base_mesh; } else { Mesh->Lods.RemoveAt(lod); break; } } unguard; } skeleton: // copy skeleton guard(ProcessSkeleton); Mesh->RefSkeleton.Empty(RefSkeleton.Num()); for (int i = 0; i < RefSkeleton.Num(); i++) { const FMeshBone &B = RefSkeleton[i]; CSkelMeshBone *Dst = new (Mesh->RefSkeleton) CSkelMeshBone; Dst->Name = B.Name; Dst->ParentIndex = B.ParentIndex; Dst->Position = CVT(B.BonePos.Position); Dst->Orientation = CVT(B.BonePos.Orientation); } unguard; // ProcessSkeleton // copy sockets int NumSockets = AttachAliases.Num(); Mesh->Sockets.Empty(NumSockets); for (int i = 0; i < NumSockets; i++) { CSkelMeshSocket *DS = new (Mesh->Sockets) CSkelMeshSocket; DS->Name = AttachAliases[i]; DS->Bone = AttachBoneNames[i]; DS->Transform = CVT(AttachCoords[i]); } Mesh->FinalizeMesh(); unguard; }
int main(int argc, char* argv[]) { uint16 bitspersample, shortv; uint32 imagewidth, imagelength; uint16 config = PLANARCONFIG_CONTIG; uint32 rowsperstrip = (uint32) -1; uint16 photometric = PHOTOMETRIC_RGB; uint16 *rmap, *gmap, *bmap; uint32 row; int cmap = -1; TIFF *in, *out; int c; extern int optind; extern char* optarg; while ((c = getopt(argc, argv, "C:c:p:r:")) != -1) switch (c) { case 'C': /* force colormap interpretation */ cmap = atoi(optarg); break; case 'c': /* compression scheme */ if (!processCompressOptions(optarg)) usage(); break; case 'p': /* planar configuration */ if (streq(optarg, "separate")) config = PLANARCONFIG_SEPARATE; else if (streq(optarg, "contig")) config = PLANARCONFIG_CONTIG; else usage(); break; case 'r': /* rows/strip */ rowsperstrip = atoi(optarg); break; case '?': usage(); /*NOTREACHED*/ } if (argc - optind != 2) usage(); in = TIFFOpen(argv[optind], "r"); if (in == NULL) return (-1); if (!TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &shortv) || shortv != PHOTOMETRIC_PALETTE) { fprintf(stderr, "%s: Expecting a palette image.\n", argv[optind]); return (-1); } if (!TIFFGetField(in, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) { fprintf(stderr, "%s: No colormap (not a valid palette image).\n", argv[optind]); return (-1); } bitspersample = 0; TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample); if (bitspersample != 8) { fprintf(stderr, "%s: Sorry, can only handle 8-bit images.\n", argv[optind]); return (-1); } out = TIFFOpen(argv[optind+1], "w"); if (out == NULL) return (-2); cpTags(in, out); TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &imagewidth); TIFFGetField(in, TIFFTAG_IMAGELENGTH, &imagelength); if (compression != (uint16)-1) TIFFSetField(out, TIFFTAG_COMPRESSION, compression); else TIFFGetField(in, TIFFTAG_COMPRESSION, &compression); switch (compression) { case COMPRESSION_JPEG: if (jpegcolormode == JPEGCOLORMODE_RGB) photometric = PHOTOMETRIC_YCBCR; else photometric = PHOTOMETRIC_RGB; TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality); TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode); break; case COMPRESSION_LZW: case COMPRESSION_DEFLATE: if (predictor != 0) TIFFSetField(out, TIFFTAG_PREDICTOR, predictor); break; } TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric); TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3); TIFFSetField(out, TIFFTAG_PLANARCONFIG, config); TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip)); (void) TIFFGetField(in, TIFFTAG_PLANARCONFIG, &shortv); if (cmap == -1) cmap = checkcmap(1<<bitspersample, rmap, gmap, bmap); if (cmap == 16) { /* * Convert 16-bit colormap to 8-bit. */ int i; for (i = (1<<bitspersample)-1; i >= 0; i--) { #define CVT(x) (((x) * 255) / ((1L<<16)-1)) rmap[i] = CVT(rmap[i]); gmap[i] = CVT(gmap[i]); bmap[i] = CVT(bmap[i]); } } { unsigned char *ibuf, *obuf; register unsigned char* pp; register uint32 x; ibuf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(in)); obuf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(out)); switch (config) { case PLANARCONFIG_CONTIG: for (row = 0; row < imagelength; row++) { if (!TIFFReadScanline(in, ibuf, row, 0)) goto done; pp = obuf; for (x = 0; x < imagewidth; x++) { *pp++ = rmap[ibuf[x]]; *pp++ = gmap[ibuf[x]]; *pp++ = bmap[ibuf[x]]; } if (!TIFFWriteScanline(out, obuf, row, 0)) goto done; } break; case PLANARCONFIG_SEPARATE: for (row = 0; row < imagelength; row++) { if (!TIFFReadScanline(in, ibuf, row, 0)) goto done; for (pp = obuf, x = 0; x < imagewidth; x++) *pp++ = rmap[ibuf[x]]; if (!TIFFWriteScanline(out, obuf, row, 0)) goto done; for (pp = obuf, x = 0; x < imagewidth; x++) *pp++ = gmap[ibuf[x]]; if (!TIFFWriteScanline(out, obuf, row, 0)) goto done; for (pp = obuf, x = 0; x < imagewidth; x++) *pp++ = bmap[ibuf[x]]; if (!TIFFWriteScanline(out, obuf, row, 0)) goto done; } break; } _TIFFfree(ibuf); _TIFFfree(obuf); } done: (void) TIFFClose(in); (void) TIFFClose(out); return (0); }
// Returns false if the output value is not the same as the number's value, which // can occur due to accuracy loss and the value not being within the target range. static Boolean __CFNumberGetValue(CFNumberRef number, CFNumberType type, void* valuePtr) { #define CVT(SRC_TYPE, DST_TYPE, DST_MIN, DST_MAX) \ do { \ SRC_TYPE sv; \ memmove(&sv, data, sizeof(SRC_TYPE)); \ DST_TYPE dv = (sv < DST_MIN) ? \ (DST_TYPE)(DST_MIN) : \ (DST_TYPE)((DST_MAX < sv) ? DST_MAX : sv); \ memmove(valuePtr, &dv, sizeof(DST_TYPE)); \ SRC_TYPE vv = (SRC_TYPE)dv; \ return (vv == sv); \ } while (0) #define CVT128ToInt(SRC_TYPE, DST_TYPE, DST_MIN, DST_MAX) \ do { \ SRC_TYPE sv; \ memmove(&sv, data, sizeof(SRC_TYPE)); \ DST_TYPE dv; Boolean noLoss = false; \ if (0 < sv.high || (!sv.high && (int64_t)DST_MAX < sv.low)) { \ dv = DST_MAX; \ } else if (sv.high < -1 || (-1 == sv.high && sv.low < (int64_t)DST_MIN)) { \ dv = DST_MIN; \ } else { \ dv = (DST_TYPE)sv.low; \ noLoss = true; \ } \ memmove(valuePtr, &dv, sizeof(DST_TYPE)); \ return noLoss; \ } while (0) /*****/ type = __CFNumberTypeTable[type].canonicalType; CFNumberType ntype = __CFNumberGetType(number); const void* data = &(number->_pad); switch (type) { case kCFNumberSInt8Type: if (__CFNumberTypeTable[ntype].floatBit) { if (!__CFNumberTypeTable[ntype].storageBit) { CVT(Float32, int8_t, INT8_MIN, INT8_MAX); } else { CVT(Float64, int8_t, INT8_MIN, INT8_MAX); } } else { if (!__CFNumberTypeTable[ntype].storageBit) { CVT(int64_t, int8_t, INT8_MIN, INT8_MAX); } else { CVT128ToInt(CFSInt128Struct, int8_t, INT8_MIN, INT8_MAX); } } return true; case kCFNumberSInt16Type: if (__CFNumberTypeTable[ntype].floatBit) { if (!__CFNumberTypeTable[ntype].storageBit) { CVT(Float32, int16_t, INT16_MIN, INT16_MAX); } else { CVT(Float64, int16_t, INT16_MIN, INT16_MAX); } } else { if (!__CFNumberTypeTable[ntype].storageBit) { CVT(int64_t, int16_t, INT16_MIN, INT16_MAX); } else { CVT128ToInt(CFSInt128Struct, int16_t, INT16_MIN, INT16_MAX); } } return true; case kCFNumberSInt32Type: if (__CFNumberTypeTable[ntype].floatBit) { if (!__CFNumberTypeTable[ntype].storageBit) { CVT(Float32, int32_t, INT32_MIN, INT32_MAX); } else { CVT(Float64, int32_t, INT32_MIN, INT32_MAX); } } else { if (!__CFNumberTypeTable[ntype].storageBit) { CVT(int64_t, int32_t, INT32_MIN, INT32_MAX); } else { CVT128ToInt(CFSInt128Struct, int32_t, INT32_MIN, INT32_MAX); } } return true; case kCFNumberSInt64Type: if (__CFNumberTypeTable[ntype].floatBit) { if (!__CFNumberTypeTable[ntype].storageBit) { CVT(Float32, int64_t, INT64_MIN, INT64_MAX); } else { CVT(Float64, int64_t, INT64_MIN, INT64_MAX); } } else { if (!__CFNumberTypeTable[ntype].storageBit) { memmove(valuePtr, data, 8); } else { CVT128ToInt(CFSInt128Struct, int64_t, INT64_MIN, INT64_MAX); } } return true; case kCFNumberSInt128Type: if (__CFNumberTypeTable[ntype].floatBit) { if (!__CFNumberTypeTable[ntype].storageBit) { Float32 f; memmove(&f, data, 4); Float64 d = f; CFSInt128Struct i; __CFSInt128FromFloat64(&i, &d); memmove(valuePtr, &i, 16); Float64 d2; __CFSInt128ToFloat64(&d2, &i); Float32 f2 = (Float32)d2; return (f2 == f); } else { Float64 d; memmove(&d, data, 8); CFSInt128Struct i; __CFSInt128FromFloat64(&i, &d); memmove(valuePtr, &i, 16); Float64 d2; __CFSInt128ToFloat64(&d2, &i); return (d2 == d); } } else { if (!__CFNumberTypeTable[ntype].storageBit) { int64_t j; memmove(&j, data, 8); CFSInt128Struct i; i.low = j; i.high = (j < 0) ? -1LL : 0LL; memmove(valuePtr, &i, 16); } else { memmove(valuePtr, data, 16); } } return true; case kCFNumberFloat32Type: if (__CFNumberTypeTable[ntype].floatBit) { if (!__CFNumberTypeTable[ntype].storageBit) { memmove(valuePtr, data, 4); } else { double d; memmove(&d, data, 8); if (isnan(d)) { uint32_t l = 0x7fc00000; memmove(valuePtr, &l, 4); return true; } else if (isinf(d)) { uint32_t l = 0x7f800000; if (d < 0.0) { l += 0x80000000UL; } memmove(valuePtr, &l, 4); return true; } CVT(Float64, Float32, -FLT_MAX, FLT_MAX); } } else { if (!__CFNumberTypeTable[ntype].storageBit) { CVT(int64_t, Float32, -FLT_MAX, FLT_MAX); } else { CFSInt128Struct i; memmove(&i, data, 16); Float64 d; __CFSInt128ToFloat64(&d, &i); Float32 f = (Float32)d; memmove(valuePtr, &f, 4); d = f; CFSInt128Struct i2; __CFSInt128FromFloat64(&i2, &d); return __CFSInt128Compare(&i2, &i) == kCFCompareEqualTo; } } return true; case kCFNumberFloat64Type: if (__CFNumberTypeTable[ntype].floatBit) { if (!__CFNumberTypeTable[ntype].storageBit) { float f; memmove(&f, data, 4); if (isnan(f)) { uint64_t l = DOUBLE_NAN_BITS; memmove(valuePtr, &l, 8); return true; } else if (isinf(f)) { uint64_t l = DOUBLE_POSINF_BITS; if (f < 0.0) { l += 0x8000000000000000ULL; } memmove(valuePtr, &l, 8); return true; } CVT(Float32, Float64, -DBL_MAX, DBL_MAX); } else { memmove(valuePtr, data, 8); } } else { if (!__CFNumberTypeTable[ntype].storageBit) { CVT(int64_t, Float64, -DBL_MAX, DBL_MAX); } else { CFSInt128Struct i; memmove(&i, data, 16); Float64 d; __CFSInt128ToFloat64(&d, &i); memmove(valuePtr, &d, 8); CFSInt128Struct i2; __CFSInt128FromFloat64(&i2, &d); return __CFSInt128Compare(&i2, &i) == kCFCompareEqualTo; } } return true; } return false; /*****/ #undef CVT #undef CVT128ToInt }
void USkelModel::Serialize(FArchive &Ar) { guard(USkelModel::Serialize); assert(Ar.IsLoading); // no saving ... Super::Serialize(Ar); // USkelModel data int nummeshes; int numjoints; int numframes; int numsequences; int numskins; int rootjoint; FVector PosOffset; // Offset of creature relative to base FRotator RotOffset; // Offset of creatures rotation TArray<RMesh> meshes; TArray<RJoint> joints; TArray<FRSkelAnimSeq> AnimSeqs; // Compressed animation data for sequence TArray<RAnimFrame> frames; Ar << nummeshes << numjoints << numframes << numsequences << numskins << rootjoint; Ar << meshes << joints << AnimSeqs << frames << PosOffset << RotOffset; int modelIdx; // create all meshes first, then fill them (for better view order) for (modelIdx = 0; modelIdx < meshes.Num(); modelIdx++) { // create new USkeletalMesh // use "CreateClass()" instead of "new USkeletalMesh" to allow this object to be // placed in GObjObjects array and be browsable in a viewer USkeletalMesh *sm = static_cast<USkeletalMesh*>(CreateClass("SkeletalMesh")); char nameBuf[256]; appSprintf(ARRAY_ARG(nameBuf), "%s_%d", Name, modelIdx); const char *name = appStrdupPool(nameBuf); Meshes.Add(sm); // setup UOnject sm->Name = name; sm->Package = Package; sm->PackageIndex = INDEX_NONE; // not really exported sm->Outer = NULL; } // create animation Anim = static_cast<UMeshAnimation*>(CreateClass("MeshAnimation")); Anim->Name = Name; Anim->Package = Package; Anim->PackageIndex = INDEX_NONE; // not really exported Anim->Outer = NULL; ConvertRuneAnimations(*Anim, joints, AnimSeqs); Anim->ConvertAnims(); //?? second conversion // get baseframe assert(strcmp(Anim->AnimSeqs[0].Name, "baseframe") == 0); const TArray<AnalogTrack> &BaseAnim = Anim->Moves[0].AnimTracks; // compute bone coordinates TArray<CCoords> BoneCoords; BuildSkeleton(BoneCoords, joints, BaseAnim); // setup meshes for (modelIdx = 0; modelIdx < meshes.Num(); modelIdx++) { int i, j; const RMesh &src = meshes[modelIdx]; USkeletalMesh *sm = Meshes[modelIdx]; sm->Animation = Anim; // setup ULodMesh sm->RotOrigin = RotOffset; sm->MeshScale.Set(1, 1, 1); sm->MeshOrigin = PosOffset; // copy skeleton sm->RefSkeleton.Empty(joints.Num()); for (i = 0; i < joints.Num(); i++) { const RJoint &J = joints[i]; FMeshBone *B = new(sm->RefSkeleton) FMeshBone; B->Name = J.name; B->Flags = 0; B->ParentIndex = (J.parent > 0) ? J.parent : 0; // -1 -> 0 // copy bone orientations from base animation frame B->BonePos.Orientation = BaseAnim[i].KeyQuat[0]; B->BonePos.Position = BaseAnim[i].KeyPos[0]; } // copy vertices int VertexCount = sm->VertexCount = src.verts.Num(); sm->Points.Empty(VertexCount); for (i = 0; i < VertexCount; i++) { const RVertex &v1 = src.verts[i]; FVector *V = new(sm->Points) FVector; // transform point from local bone space to model space BoneCoords[v1.joint1].UnTransformPoint(CVT(v1.point1), CVT(*V)); } // copy triangles and create wedges // here we create 3 wedges for each triangle. // it is possible to reduce number of wedges by finding duplicates, but we don't // need it here ... int TrisCount = src.tris.Num(); sm->Triangles.Empty(TrisCount); sm->Wedges.Empty(TrisCount * 3); int numMaterials = 0; // should detect real material count for (i = 0; i < TrisCount; i++) { const RTriangle &tri = src.tris[i]; // create triangle VTriangle *T = new(sm->Triangles) VTriangle; T->MatIndex = tri.polygroup; if (numMaterials <= tri.polygroup) numMaterials = tri.polygroup+1; // create wedges for (j = 0; j < 3; j++) { T->WedgeIndex[j] = sm->Wedges.Num(); FMeshWedge *W = new(sm->Wedges) FMeshWedge; W->iVertex = tri.vIndex[j]; W->TexUV = tri.tex[j]; } // reverse order of triangle vertices Exchange(T->WedgeIndex[0], T->WedgeIndex[1]); } // build influences for (i = 0; i < VertexCount; i++) { const RVertex &v1 = src.verts[i]; FVertInfluence *Inf = new(sm->VertInfluences) FVertInfluence; Inf->PointIndex = i; Inf->BoneIndex = v1.joint1; Inf->Weight = v1.weight1; if (Inf->Weight != 1.0f) { // influence for 2nd bone Inf = new(sm->VertInfluences) FVertInfluence; Inf->PointIndex = i; Inf->BoneIndex = v1.joint2; Inf->Weight = 1.0f - v1.weight1; } } // create materials for (i = 0; i < numMaterials; i++) { const char *texName = src.PolyGroupSkinNames[i]; FMeshMaterial *M1 = new(sm->Materials) FMeshMaterial; M1->PolyFlags = src.GroupFlags[i]; M1->TextureIndex = sm->Textures.Num(); if (strcmp(texName, "None") == 0) { // texture should be set from script sm->Textures.Add(NULL); continue; } // find texture in object's package int texExportIdx = Package->FindExport(texName); if (texExportIdx == INDEX_NONE) { appPrintf("ERROR: unable to find export \"%s\" for mesh \"%s\" (%d)\n", texName, Name, modelIdx); continue; } // load and remember texture UMaterial *Tex = static_cast<UMaterial*>(Package->CreateExport(texExportIdx)); sm->Textures.Add(Tex); } // setup UPrimitive properties using 1st animation frame // note: this->BoundingBox and this->BoundingSphere are null const RAnimFrame &F = frames[0]; assert(strcmp(AnimSeqs[0].Name, "baseframe") == 0 && AnimSeqs[0].StartFrame == 0); CVec3 mins, maxs; sm->BoundingBox = F.bounds; mins = CVT(F.bounds.Min); maxs = CVT(F.bounds.Max); CVec3 ¢er = CVT(sm->BoundingSphere); for (i = 0; i < 3; i++) center[i] = (mins[i] + maxs[i]) / 2; sm->BoundingSphere.R = VectorDistance(center, mins); // create CSkeletalMesh sm->ConvertMesh(); } unguard; }
static void PS_Lvl2colorspace(FILE* fd, TIFF* tif) { uint16 *rmap, *gmap, *bmap; int i, num_colors; const char * colorspace_p; switch ( photometric ) { case PHOTOMETRIC_SEPARATED: colorspace_p = "CMYK"; break; case PHOTOMETRIC_RGB: colorspace_p = "RGB"; break; default: colorspace_p = "Gray"; } /* * Set up PostScript Level 2 colorspace according to * section 4.8 in the PostScript refenence manual. */ fputs("% PostScript Level 2 only.\n", fd); if (photometric != PHOTOMETRIC_PALETTE) { if (photometric == PHOTOMETRIC_YCBCR) { /* MORE CODE HERE */ } fprintf(fd, "/Device%s setcolorspace\n", colorspace_p ); return; } /* * Set up an indexed/palette colorspace */ num_colors = (1 << bitspersample); if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) { TIFFError(filename, "Palette image w/o \"Colormap\" tag"); return; } if (checkcmap(tif, num_colors, rmap, gmap, bmap) == 16) { /* * Convert colormap to 8-bits values. */ #define CVT(x) (((x) * 255) / ((1L<<16)-1)) for (i = 0; i < num_colors; i++) { rmap[i] = CVT(rmap[i]); gmap[i] = CVT(gmap[i]); bmap[i] = CVT(bmap[i]); } #undef CVT } fprintf(fd, "[ /Indexed /DeviceRGB %d", num_colors - 1); if (ascii85) { Ascii85Init(); fputs("\n<~", fd); ascii85breaklen -= 2; } else fputs(" <", fd); for (i = 0; i < num_colors; i++) { if (ascii85) { Ascii85Put(rmap[i], fd); Ascii85Put(gmap[i], fd); Ascii85Put(bmap[i], fd); } else { fputs((i % 8) ? " " : "\n ", fd); fprintf(fd, "%02x%02x%02x", rmap[i], gmap[i], bmap[i]); } } if (ascii85) Ascii85Flush(fd); else fputs(">\n", fd); fputs("] setcolorspace\n", fd); }
void USkeleton::ConvertAnims(UAnimSequence4* Seq) { guard(USkeleton::ConvertAnims); CAnimSet* AnimSet = ConvertedAnim; if (!AnimSet) { AnimSet = new CAnimSet(this); ConvertedAnim = AnimSet; // Copy bone names AnimSet->TrackBoneNames.Empty(ReferenceSkeleton.RefBoneInfo.Num()); for (int i = 0; i < ReferenceSkeleton.RefBoneInfo.Num(); i++) { AnimSet->TrackBoneNames.Add(ReferenceSkeleton.RefBoneInfo[i].Name); } //TODO: verify if UE4 has AnimRotationOnly stuff AnimSet->AnimRotationOnly = false; } if (!Seq) return; // allow calling ConvertAnims(NULL) to create empty AnimSet // DBG("----------- Skeleton %s: %d seq, %d bones -----------\n", Name, Anims.Num(), ReferenceSkeleton.RefBoneInfo.Num()); int NumTracks = Seq->GetNumTracks(); #if DEBUG_DECOMPRESS appPrintf("Sequence %s: %d bones, %d offsets (%g per bone), %d frames, %d compressed data\n" " trans %s, rot %s, scale %s, key %s\n", Seq->Name, NumTracks, Seq->CompressedTrackOffsets.Num(), Seq->CompressedTrackOffsets.Num() / (float)NumTracks, Seq->NumFrames, Seq->CompressedByteStream.Num(), EnumToName(Seq->TranslationCompressionFormat), EnumToName(Seq->RotationCompressionFormat), EnumToName(Seq->ScaleCompressionFormat), EnumToName(Seq->KeyEncodingFormat) ); for (int i2 = 0; i2 < Seq->CompressedTrackOffsets.Num(); /*empty*/) { if (Seq->KeyEncodingFormat != AKF_PerTrackCompression) { FName BoneName = ReferenceSkeleton.RefBoneInfo[Seq->GetTrackBoneIndex(i2/4)].Name; int TransOffset = Seq->CompressedTrackOffsets[i2 ]; int TransKeys = Seq->CompressedTrackOffsets[i2+1]; int RotOffset = Seq->CompressedTrackOffsets[i2+2]; int RotKeys = Seq->CompressedTrackOffsets[i2+3]; appPrintf(" [%d] = trans %d[%d] rot %d[%d] - %s\n", i2/4, TransOffset, TransKeys, RotOffset, RotKeys, *BoneName); i2 += 4; } else { FName BoneName = ReferenceSkeleton.RefBoneInfo[Seq->GetTrackBoneIndex(i2/2)].Name; int TransOffset = Seq->CompressedTrackOffsets[i2 ]; int RotOffset = Seq->CompressedTrackOffsets[i2+1]; appPrintf(" [%d] = trans %d rot %d - %s\n", i2/2, TransOffset, RotOffset, *BoneName); i2 += 2; } } #endif // DEBUG_DECOMPRESS // some checks int offsetsPerBone = 4; if (Seq->KeyEncodingFormat == AKF_PerTrackCompression) offsetsPerBone = 2; if (Seq->CompressedTrackOffsets.Num() != NumTracks * offsetsPerBone && !Seq->RawAnimationData.Num()) { appNotify("AnimSequence %s has wrong CompressedTrackOffsets size (has %d, expected %d), removing track", Seq->Name, Seq->CompressedTrackOffsets.Num(), NumTracks * offsetsPerBone); return; } // create CAnimSequence CAnimSequence *Dst = new CAnimSequence; AnimSet->Sequences.Add(Dst); Dst->Name = Seq->Name; Dst->NumFrames = Seq->NumFrames; Dst->Rate = Seq->NumFrames / Seq->SequenceLength * Seq->RateScale; // bone tracks ... Dst->Tracks.Empty(NumTracks); FMemReader Reader(Seq->CompressedByteStream.GetData(), Seq->CompressedByteStream.Num()); Reader.SetupFrom(*Package); bool HasTimeTracks = (Seq->KeyEncodingFormat == AKF_VariableKeyLerp); for (int BoneIndex = 0; BoneIndex < ReferenceSkeleton.RefBoneInfo.Num(); BoneIndex++) { CAnimTrack *A = new (Dst->Tracks) CAnimTrack; int TrackIndex = Seq->FindTrackForBoneIndex(BoneIndex); if (TrackIndex < 0) { // this track has no animation, use static pose from ReferenceSkeleton const FTransform& RefPose = ReferenceSkeleton.RefBonePose[BoneIndex]; A->KeyPos.Add(CVT(RefPose.Translation)); A->KeyQuat.Add(CVT(RefPose.Rotation)); //!! RefPose.Scale3D continue; } int k; if (!Seq->CompressedTrackOffsets.Num()) //?? or if RawAnimData.Num() != 0 { // using RawAnimData array assert(Seq->RawAnimationData.Num() == NumTracks); CopyArray(A->KeyPos, CVT(Seq->RawAnimationData[TrackIndex].PosKeys)); CopyArray(A->KeyQuat, CVT(Seq->RawAnimationData[TrackIndex].RotKeys)); CopyArray(A->KeyTime, Seq->RawAnimationData[TrackIndex].KeyTimes); // may be empty for (int k = 0; k < A->KeyTime.Num(); k++) A->KeyTime[k] *= Dst->Rate; continue; } FVector Mins, Ranges; // common ... static const CVec3 nullVec = { 0, 0, 0 }; static const CQuat nullQuat = { 0, 0, 0, 1 }; int offsetIndex = TrackIndex * offsetsPerBone; // PARAGON has invalid data inside some animation tracks. Not sure if game engine ignores them // or trying to process (this game has holes in data due to wrong pointers in CompressedTrackOffsets). // This causes garbage data to appear instead of real animation track header, with wrong compression // method etc. We're going to skip such tracks with displaying a warning message. if (0) // this is just a placeholder for error handler - it should be located somewhere { track_error: AnimSet->Sequences.RemoveSingle(Dst); delete Dst; return; } //---------------------------------------------- // decode AKF_PerTrackCompression data //---------------------------------------------- if (Seq->KeyEncodingFormat == AKF_PerTrackCompression) { // this format uses different key storage guard(PerTrackCompression); assert(Seq->TranslationCompressionFormat == ACF_Identity); assert(Seq->RotationCompressionFormat == ACF_Identity); int TransOffset = Seq->CompressedTrackOffsets[offsetIndex ]; int RotOffset = Seq->CompressedTrackOffsets[offsetIndex+1]; uint32 PackedInfo; AnimationCompressionFormat KeyFormat; int ComponentMask; int NumKeys; #define DECODE_PER_TRACK_INFO(info) \ KeyFormat = (AnimationCompressionFormat)(info >> 28); \ ComponentMask = (info >> 24) & 0xF; \ NumKeys = info & 0xFFFFFF; \ HasTimeTracks = (ComponentMask & 8) != 0; guard(TransKeys); // read translation keys if (TransOffset == -1) { A->KeyPos.Add(nullVec); DBG(" [%d] no translation data\n", TrackIndex); } else { Reader.Seek(TransOffset); Reader << PackedInfo; DECODE_PER_TRACK_INFO(PackedInfo); A->KeyPos.Empty(NumKeys); DBG(" [%d] trans: fmt=%d (%s), %d keys, mask %d\n", TrackIndex, KeyFormat, EnumToName(KeyFormat), NumKeys, ComponentMask ); if (KeyFormat == ACF_IntervalFixed32NoW) { // read mins/maxs Mins.Set(0, 0, 0); Ranges.Set(0, 0, 0); if (ComponentMask & 1) Reader << Mins.X << Ranges.X; if (ComponentMask & 2) Reader << Mins.Y << Ranges.Y; if (ComponentMask & 4) Reader << Mins.Z << Ranges.Z; } for (k = 0; k < NumKeys; k++) { switch (KeyFormat) { // case ACF_None: case ACF_Float96NoW: { FVector v; if (ComponentMask & 7) { v.Set(0, 0, 0); if (ComponentMask & 1) Reader << v.X; if (ComponentMask & 2) Reader << v.Y; if (ComponentMask & 4) Reader << v.Z; } else { // ACF_Float96NoW has a special case for ((ComponentMask & 7) == 0) Reader << v; } A->KeyPos.Add(CVT(v)); } break; TPR(ACF_IntervalFixed32NoW, FVectorIntervalFixed32) case ACF_Fixed48NoW: { uint16 X, Y, Z; CVec3 v; v.Set(0, 0, 0); if (ComponentMask & 1) { Reader << X; v[0] = DecodeFixed48_PerTrackComponent<7>(X); } if (ComponentMask & 2) { Reader << Y; v[1] = DecodeFixed48_PerTrackComponent<7>(Y); } if (ComponentMask & 4) { Reader << Z; v[2] = DecodeFixed48_PerTrackComponent<7>(Z); } A->KeyPos.Add(v); } break; case ACF_Identity: A->KeyPos.Add(nullVec); break; default: { char buf[1024]; Seq->GetFullName(buf, 1024); appNotify("%s: unknown translation compression method: %d (%s) - dropping track", buf, KeyFormat, EnumToName(KeyFormat)); goto track_error; } } } // align to 4 bytes Reader.Seek(Align(Reader.Tell(), 4)); if (HasTimeTracks) ReadTimeArray(Reader, NumKeys, A->KeyPosTime, Seq->NumFrames); } unguard; guard(RotKeys); // read rotation keys if (RotOffset == -1) { A->KeyQuat.Add(nullQuat); DBG(" [%d] no rotation data\n", TrackIndex); } else { Reader.Seek(RotOffset); Reader << PackedInfo; DECODE_PER_TRACK_INFO(PackedInfo); A->KeyQuat.Empty(NumKeys); DBG(" [%d] rot : fmt=%d (%s), %d keys, mask %d\n", TrackIndex, KeyFormat, EnumToName(KeyFormat), NumKeys, ComponentMask ); if (KeyFormat == ACF_IntervalFixed32NoW) { // read mins/maxs Mins.Set(0, 0, 0); Ranges.Set(0, 0, 0); if (ComponentMask & 1) Reader << Mins.X << Ranges.X; if (ComponentMask & 2) Reader << Mins.Y << Ranges.Y; if (ComponentMask & 4) Reader << Mins.Z << Ranges.Z; } for (k = 0; k < NumKeys; k++) { switch (KeyFormat) { // TR (ACF_None, FQuat) case ACF_Float96NoW: { FQuatFloat96NoW q; Reader << q; FQuat q2 = q; // convert A->KeyQuat.Add(CVT(q2)); } break; case ACF_Fixed48NoW: { FQuatFixed48NoW q; q.X = q.Y = q.Z = 32767; // corresponds to 0 if (ComponentMask & 1) Reader << q.X; if (ComponentMask & 2) Reader << q.Y; if (ComponentMask & 4) Reader << q.Z; FQuat q2 = q; // convert A->KeyQuat.Add(CVT(q2)); } break; TR (ACF_Fixed32NoW, FQuatFixed32NoW) TRR(ACF_IntervalFixed32NoW, FQuatIntervalFixed32NoW) TR (ACF_Float32NoW, FQuatFloat32NoW) case ACF_Identity: A->KeyQuat.Add(nullQuat); break; default: { char buf[1024]; Seq->GetFullName(buf, 1024); appNotify("%s: unknown rotation compression method: %d (%s) - dropping track", buf, KeyFormat, EnumToName(KeyFormat)); goto track_error; } } } // align to 4 bytes Reader.Seek(Align(Reader.Tell(), 4)); if (HasTimeTracks) ReadTimeArray(Reader, NumKeys, A->KeyQuatTime, Seq->NumFrames); } unguard; unguard; continue; // end of AKF_PerTrackCompression block ... } //---------------------------------------------- // end of AKF_PerTrackCompression decoder //---------------------------------------------- // read animations int TransOffset = Seq->CompressedTrackOffsets[offsetIndex ]; int TransKeys = Seq->CompressedTrackOffsets[offsetIndex+1]; int RotOffset = Seq->CompressedTrackOffsets[offsetIndex+2]; int RotKeys = Seq->CompressedTrackOffsets[offsetIndex+3]; // appPrintf("[%d:%d:%d] : %d[%d] %d[%d] %d[%d]\n", j, Seq->RotationCompressionFormat, Seq->TranslationCompressionFormat, TransOffset, TransKeys, RotOffset, RotKeys, ScaleOffset, ScaleKeys); A->KeyPos.Empty(TransKeys); A->KeyQuat.Empty(RotKeys); // read translation keys if (TransKeys) { Reader.Seek(TransOffset); AnimationCompressionFormat TranslationCompressionFormat = Seq->TranslationCompressionFormat; if (TransKeys == 1) TranslationCompressionFormat = ACF_None; // single key is stored without compression // read mins/ranges if (TranslationCompressionFormat == ACF_IntervalFixed32NoW) { Reader << Mins << Ranges; } for (k = 0; k < TransKeys; k++) { switch (TranslationCompressionFormat) { TP (ACF_None, FVector) TP (ACF_Float96NoW, FVector) TPR(ACF_IntervalFixed32NoW, FVectorIntervalFixed32) TP (ACF_Fixed48NoW, FVectorFixed48) case ACF_Identity: A->KeyPos.Add(nullVec); break; default: appError("Unknown translation compression method: %d (%s)", TranslationCompressionFormat, EnumToName(TranslationCompressionFormat)); } } // align to 4 bytes Reader.Seek(Align(Reader.Tell(), 4)); if (HasTimeTracks) ReadTimeArray(Reader, TransKeys, A->KeyPosTime, Seq->NumFrames); } else { // A->KeyPos.Add(nullVec); // appNotify("No translation keys!"); }
int main(int argc, char* argv[]) { uint32 rowsperstrip = (uint32) -1; TIFF *in, *out; uint32 w, h; uint16 samplesperpixel; uint16 bitspersample; uint16 config; uint16 photometric; uint16* red; uint16* green; uint16* blue; tsize_t rowsize; register uint32 row; register tsample_t s; unsigned char *inbuf, *outbuf; char thing[1024]; int c; extern int optind; extern char *optarg; while ((c = getopt(argc, argv, "c:r:R:G:B:")) != -1) switch (c) { case 'c': /* compression scheme */ if (!processCompressOptions(optarg)) usage(); break; case 'r': /* rows/strip */ rowsperstrip = atoi(optarg); break; case 'R': RED = PCT(atoi(optarg)); break; case 'G': GREEN = PCT(atoi(optarg)); break; case 'B': BLUE = PCT(atoi(optarg)); break; case '?': usage(); /*NOTREACHED*/ } if (argc - optind < 2) usage(); in = TIFFOpen(argv[optind], "r"); if (in == NULL) return (-1); photometric = 0; TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric); if (photometric != PHOTOMETRIC_RGB && photometric != PHOTOMETRIC_PALETTE ) { fprintf(stderr, "%s: Bad photometric; can only handle RGB and Palette images.\n", argv[optind]); return (-1); } TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); if (samplesperpixel != 1 && samplesperpixel != 3) { fprintf(stderr, "%s: Bad samples/pixel %u.\n", argv[optind], samplesperpixel); return (-1); } TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample); if (bitspersample != 8) { fprintf(stderr, " %s: Sorry, only handle 8-bit samples.\n", argv[optind]); return (-1); } TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(in, TIFFTAG_IMAGELENGTH, &h); TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config); out = TIFFOpen(argv[optind+1], "w"); if (out == NULL) return (-1); cpTags(in, out); TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); if (compression != (uint16) -1) { TIFFSetField(out, TIFFTAG_COMPRESSION, compression); switch (compression) { case COMPRESSION_JPEG: TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality); TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode); break; case COMPRESSION_LZW: case COMPRESSION_DEFLATE: if (predictor != 0) TIFFSetField(out, TIFFTAG_PREDICTOR, predictor); break; } } TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); sprintf(thing, "B&W version of %s", argv[optind]); TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, thing); TIFFSetField(out, TIFFTAG_SOFTWARE, "tiff2bw"); outbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out)); TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, rowsperstrip)); #define pack(a,b) ((a)<<8 | (b)) switch (pack(photometric, config)) { case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_CONTIG): case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_SEPARATE): TIFFGetField(in, TIFFTAG_COLORMAP, &red, &green, &blue); /* * Convert 16-bit colormap to 8-bit (unless it looks * like an old-style 8-bit colormap). */ if (checkcmap(in, 1<<bitspersample, red, green, blue) == 16) { int i; #define CVT(x) (((x) * 255L) / ((1L<<16)-1)) for (i = (1<<bitspersample)-1; i >= 0; i--) { red[i] = CVT(red[i]); green[i] = CVT(green[i]); blue[i] = CVT(blue[i]); } #undef CVT } inbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in)); for (row = 0; row < h; row++) { if (TIFFReadScanline(in, inbuf, row, 0) < 0) break; compresspalette(outbuf, inbuf, w, red, green, blue); if (TIFFWriteScanline(out, outbuf, row, 0) < 0) break; } break; case pack(PHOTOMETRIC_RGB, PLANARCONFIG_CONTIG): inbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in)); for (row = 0; row < h; row++) { if (TIFFReadScanline(in, inbuf, row, 0) < 0) break; compresscontig(outbuf, inbuf, w); if (TIFFWriteScanline(out, outbuf, row, 0) < 0) break; } break; case pack(PHOTOMETRIC_RGB, PLANARCONFIG_SEPARATE): rowsize = TIFFScanlineSize(in); inbuf = (unsigned char *)_TIFFmalloc(3*rowsize); for (row = 0; row < h; row++) { for (s = 0; s < 3; s++) if (TIFFReadScanline(in, inbuf+s*rowsize, row, s) < 0) return (-1); compresssep(outbuf, inbuf, inbuf+rowsize, inbuf+2*rowsize, w); if (TIFFWriteScanline(out, outbuf, row, 0) < 0) break; } break; } #undef pack TIFFClose(out); return (0); }
unsigned char * simage_tiff_load(std::istream& fin, int& width_ret, int& height_ret, int& numComponents_ret, uint16& bitspersample) { TIFF *in; uint16 dataType; uint16 samplesperpixel; uint16 photometric; uint32 w, h; uint16 config; uint16* red; uint16* green; uint16* blue; unsigned char *inbuf = NULL; tsize_t rowsize; uint32 row; int format; unsigned char *buffer; int width; int height; unsigned char *currPtr; TIFFSetErrorHandler(tiff_error); TIFFSetWarningHandler(tiff_warn); in = TIFFClientOpen("inputstream", "r", (thandle_t)&fin, libtiffStreamReadProc, //Custom read function libtiffStreamWriteProc, //Custom write function libtiffStreamSeekProc, //Custom seek function libtiffStreamCloseProc, //Custom close function libtiffStreamSizeProc, //Custom size function libtiffStreamMapProc, //Custom map function libtiffStreamUnmapProc); //Custom unmap function if (in == NULL) { tifferror = ERR_OPEN; return NULL; } if (TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric) == 1) { if (photometric != PHOTOMETRIC_RGB && photometric != PHOTOMETRIC_PALETTE && photometric != PHOTOMETRIC_MINISWHITE && photometric != PHOTOMETRIC_MINISBLACK) { OSG_NOTICE << "Photometric type "<<photometric<<" not handled; can only handle Grayscale, RGB and Palette images" << std::endl; TIFFClose(in); tifferror = ERR_UNSUPPORTED; return NULL; } } else { tifferror = ERR_READ; TIFFClose(in); return NULL; } if (TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel) == 1) { if (samplesperpixel != 1 && samplesperpixel != 2 && samplesperpixel != 3 && samplesperpixel != 4) { OSG_DEBUG << "Bad samples/pixel" << std::endl; tifferror = ERR_UNSUPPORTED; TIFFClose(in); return NULL; } } else { tifferror = ERR_READ; TIFFClose(in); return NULL; } if (TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample) == 1) { if (bitspersample != 8 && bitspersample != 16 && bitspersample != 32) { OSG_NOTICE << "can only handle 8, 16 and 32 bit samples" << std::endl; TIFFClose(in); tifferror = ERR_UNSUPPORTED; return NULL; } } else { tifferror = ERR_READ; TIFFClose(in); return NULL; } if (TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w) != 1 || TIFFGetField(in, TIFFTAG_IMAGELENGTH, &h) != 1 || TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config) != 1) { TIFFClose(in); tifferror = ERR_READ; return NULL; } TIFFGetField(in, TIFFTAG_DATATYPE, &dataType); OSG_INFO<<"TIFFTAG_DATATYPE="<<dataType<<std::endl; /* if (photometric == PHOTOMETRIC_MINISWHITE || photometric == PHOTOMETRIC_MINISBLACK) format = 1; else format = 3; */ // if it has a palette, data returned is 3 byte rgb // so set format to 3. if (photometric == PHOTOMETRIC_PALETTE) format = 3; else format = samplesperpixel * bitspersample / 8; int bytespersample = bitspersample / 8; int bytesperpixel = bytespersample * samplesperpixel; OSG_INFO<<"format="<<format<<std::endl; OSG_INFO<<"bytespersample="<<bytespersample<<std::endl; OSG_INFO<<"bytesperpixel="<<bytesperpixel<<std::endl; buffer = new unsigned char [w*h*format]; if (!buffer) { tifferror = ERR_MEM; TIFFClose(in); return NULL; } // initialize memory for(unsigned char* ptr=buffer;ptr<buffer+w*h*format;++ptr) *ptr = 0; width = w; height = h; currPtr = buffer + (h-1)*w*format; tifferror = ERR_NO_ERROR; switch (pack(photometric, config)) { case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_CONTIG): case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_CONTIG): case pack(PHOTOMETRIC_MINISWHITE, PLANARCONFIG_SEPARATE): case pack(PHOTOMETRIC_MINISBLACK, PLANARCONFIG_SEPARATE): inbuf = new unsigned char [TIFFScanlineSize(in)]; for (row = 0; row < h; row++) { if (TIFFReadScanline(in, inbuf, row, 0) < 0) { tifferror = ERR_READ; break; } invert_row(currPtr, inbuf, samplesperpixel*w, photometric == PHOTOMETRIC_MINISWHITE, bitspersample); currPtr -= format*w; } break; case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_CONTIG): case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_SEPARATE): if (TIFFGetField(in, TIFFTAG_COLORMAP, &red, &green, &blue) != 1) tifferror = ERR_READ; /* */ /* Convert 16-bit colormap to 8-bit (unless it looks */ /* like an old-style 8-bit colormap). */ /* */ if (!tifferror && checkcmap(1<<bitspersample, red, green, blue) == 16) { int i; for (i = (1<<bitspersample)-1; i >= 0; i--) { red[i] = CVT(red[i]); green[i] = CVT(green[i]); blue[i] = CVT(blue[i]); } } inbuf = new unsigned char [TIFFScanlineSize(in)]; for (row = 0; row < h; row++) { if (TIFFReadScanline(in, inbuf, row, 0) < 0) { tifferror = ERR_READ; break; } remap_row(currPtr, inbuf, w, red, green, blue); currPtr -= format*w; } break; case pack(PHOTOMETRIC_RGB, PLANARCONFIG_CONTIG): inbuf = new unsigned char [TIFFScanlineSize(in)]; for (row = 0; row < h; row++) { if (TIFFReadScanline(in, inbuf, row, 0) < 0) { tifferror = ERR_READ; break; } memcpy(currPtr, inbuf, format*w); currPtr -= format*w; } break; case pack(PHOTOMETRIC_RGB, PLANARCONFIG_SEPARATE): rowsize = TIFFScanlineSize(in); inbuf = new unsigned char [format*rowsize]; for (row = 0; !tifferror && row < h; row++) { int s; for (s = 0; s < format; s++) { if (TIFFReadScanline(in, (tdata_t)(inbuf+s*rowsize), (uint32)row, (tsample_t)s) < 0) { tifferror = ERR_READ; break; } } if (!tifferror) { if (format==3) interleave_row(currPtr, inbuf, inbuf+rowsize, inbuf+2*rowsize, w, format, bitspersample); else if (format==4) interleave_row(currPtr, inbuf, inbuf+rowsize, inbuf+2*rowsize, inbuf+3*rowsize, w, format, bitspersample); currPtr -= format*w; } } break; default: tifferror = ERR_UNSUPPORTED; break; } if (inbuf) delete [] inbuf; TIFFClose(in); if (tifferror) { if (buffer) delete [] buffer; return NULL; } width_ret = width; height_ret = height; if (photometric == PHOTOMETRIC_PALETTE) numComponents_ret = format; else numComponents_ret = samplesperpixel; return buffer; }
boolean TIFFRasterImpl::gt(u_long w, u_long h) { u_short minsamplevalue; u_short maxsamplevalue; u_short planarconfig; RGBvalue* Map = nil; if (!TIFFGetField(tif_, TIFFTAG_MINSAMPLEVALUE, &minsamplevalue)) { minsamplevalue = 0; } if (!TIFFGetField(tif_, TIFFTAG_MAXSAMPLEVALUE, &maxsamplevalue)) { maxsamplevalue = (1<<bitspersample_)-1; } switch (photometric_) { case PHOTOMETRIC_RGB: if (minsamplevalue == 0 && maxsamplevalue == 255) { break; } /* fall thru... */ case PHOTOMETRIC_MINISBLACK: case PHOTOMETRIC_MINISWHITE: { register int x, range; range = maxsamplevalue - minsamplevalue; Map = new RGBvalue[range + 1]; if (Map == nil) { TIFFError( TIFFFileName(tif_), "No space for photometric conversion table" ); return false; } if (photometric_ == PHOTOMETRIC_MINISWHITE) { for (x = 0; x <= range; x++) { Map[x] = ((range - x) * 255) / range; } } else { for (x = 0; x <= range; x++) { Map[x] = (x * 255) / range; } } if (photometric_ != PHOTOMETRIC_RGB && bitspersample_ != 8) { /* * Use photometric mapping table to construct * unpacking tables for samples < 8 bits. */ if (!makebwmap(Map)) { return false; } delete Map; /* no longer need Map, free it */ Map = nil; } break; } case PHOTOMETRIC_PALETTE: if (!TIFFGetField( tif_, TIFFTAG_COLORMAP, &redcmap_, &greencmap_, &bluecmap_) ) { TIFFError(TIFFFileName(tif_), "Missing required \"Colormap\" tag"); return (false); } /* * Convert 16-bit colormap to 8-bit (unless it looks * like an old-style 8-bit colormap). */ if ( checkcmap( 1 << bitspersample_, redcmap_, greencmap_, bluecmap_ ) == 16 ) { int i; for (i = (1 << bitspersample_) - 1; i > 0; i--) { #define CVT(x) (((x) * 255) / ((1L<<16)-1)) redcmap_[i] = (u_short) CVT(redcmap_[i]); greencmap_[i] = (u_short) CVT(greencmap_[i]); bluecmap_[i] = (u_short) CVT(bluecmap_[i]); } } if (bitspersample_ <= 8) { /* * Use mapping table and colormap to construct * unpacking tables for samples < 8 bits. */ if (!makecmap(redcmap_, greencmap_, bluecmap_)) { return false; } } break; } TIFFGetField(tif_, TIFFTAG_PLANARCONFIG, &planarconfig); boolean e; if (planarconfig == PLANARCONFIG_SEPARATE && samplesperpixel_ > 1) { e = TIFFIsTiled(tif_) ? gtTileSeparate(Map, h, w) : gtStripSeparate(Map, h, w); } else { e = TIFFIsTiled(tif_) ? gtTileContig(Map, h, w) : gtStripContig(Map, h, w); } delete Map; return e; }
BOOL CImageTIFF::Read(FILE* stream) { TIFF* m_tif = TIFFOpenEx(stream, "rb"); uint32 height=0; uint32 width=0; uint16 bitspersample=1; uint16 samplesperpixel=1; uint32 rowsperstrip=-1; uint16 photometric=0; uint16 compression=1; uint32 x, y; BOOL isRGB; BYTE *bits; //pointer to source data BYTE *bits2; //pointer to destination data try{ //check if it's a tiff file if (!m_tif) throw "Error encountered while opening TIFF file"; m_info.nNumFrames=0; while(TIFFSetDirectory(m_tif,(uint16)m_info.nNumFrames)) m_info.nNumFrames++; if (!TIFFSetDirectory(m_tif, (uint16)m_info.nFrame)) throw "Error: page not present in TIFF file"; //get image m_info TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); if (compression == COMPRESSION_LZW) throw "LZW compression is no longer supported due to Unisys patent enforcement"; TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); m_header.biWidth = width; m_header.biHeight = height; m_header.biClrUsed=0; m_info.nBkgndIndex =-1; isRGB = (bitspersample >= 8) && (photometric == PHOTOMETRIC_RGB) || (photometric == PHOTOMETRIC_YCBCR) || (photometric == PHOTOMETRIC_SEPARATED) || (photometric == PHOTOMETRIC_LOGLUV); if (isRGB){ m_header.biBitCount=24; m_info.bColorType = COLORTYPE_COLOR; }else{ m_info.bColorType = COLORTYPE_PALETTE; if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)){ if (bitspersample == 1){ m_header.biBitCount=1; //B&W image m_header.biClrUsed =2; } else { m_header.biBitCount=8; //gray scale m_header.biClrUsed =256; } } else if (bitspersample == 4) { m_header.biBitCount=4; // 16 colors m_header.biClrUsed=16; } else { m_header.biBitCount=8; //256 colors m_header.biClrUsed=256; } } Create(m_header.biWidth,m_header.biHeight,m_header.biBitCount); //image creation if (isRGB) { // Read the whole image into one big RGBA buffer using // the traditional TIFFReadRGBAImage() API that we trust. uint32* raster; // retrieve RGBA image uint32 *row; raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); if (raster == NULL) throw "No space for raster buffer"; // Read the image in one chunk into an RGBA array if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { _TIFFfree(raster); throw "Corrupted TIFF file!"; } // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB row = &raster[0]; bits2 = m_info.pImage; for (y = 0; y < height; y++) { bits = bits2; for (x = 0; x < width; x++) { *bits++ = (BYTE)TIFFGetB(row[x]); *bits++ = (BYTE)TIFFGetG(row[x]); *bits++ = (BYTE)TIFFGetR(row[x]); } row += width; bits2 += m_info.dwEffWidth; } _TIFFfree(raster); } else { RGBQUAD *pal; pal=(RGBQUAD*)calloc(256,sizeof(RGBQUAD)); if (pal==NULL) throw "Unable to allocate TIFF palette"; // set up the colormap based on photometric switch(photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: if (bitspersample == 1) { // Monochrome image if (photometric == PHOTOMETRIC_MINISBLACK) { pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; } } else { // need to build the scale for greyscale images if (photometric == PHOTOMETRIC_MINISBLACK) { for (int i = 0; i < 256; i++) { pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = i; } } else { for (int i = 0; i < 256; i++) { pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = 255 - i; } } } break; case PHOTOMETRIC_PALETTE: // color map indexed uint16 *red; uint16 *green; uint16 *blue; TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? BOOL Palette16Bits = FALSE; int n=1<<bitspersample; while (n-- > 0) { if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { Palette16Bits=TRUE; break; } } // load the palette in the DIB for (int i = (1 << bitspersample) - 1; i >= 0; i--) { if (Palette16Bits) { pal[i].rgbRed =(BYTE) CVT(red[i]); pal[i].rgbGreen = (BYTE) CVT(green[i]); pal[i].rgbBlue = (BYTE) CVT(blue[i]); } else { pal[i].rgbRed = (BYTE) red[i]; pal[i].rgbGreen = (BYTE) green[i]; pal[i].rgbBlue = (BYTE) blue[i]; } } break; } SetPalette(pal,m_header.biClrUsed); //palette assign free(pal); // read the tiff lines and save them in the DIB uint32 nrow; uint32 ys; int line = CalculateLine(width, bitspersample * samplesperpixel); // int pitch = CalculatePitch(line); long bitsize= TIFFStripSize(m_tif); bits = (BYTE*)malloc(bitsize); for (ys = 0; ys < height; ys += rowsperstrip) { nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), bits, nrow * line) == -1) { free(bits); throw "Corrupted TIFF file!"; } for (y = 0; y < nrow; y++) { memcpy(m_info.pImage+m_info.dwEffWidth*(height-ys-nrow+y),bits+(nrow-y-1)*line,line); } /*if (m_header.biClrUsed==2){ for (y = 0; y < nrow; y++) { for (x = 0; x < width; x++) { SetPixelIndex(x,y+ys,(bits[y*line+(x>>3)]>>(7-x%8))&0x01); }}}*/ } free(bits); } } catch (char *message) { strncpy(m_info.szLastError,message,255); if (m_tif) TIFFClose(m_tif); return FALSE; } TIFFClose(m_tif); return TRUE; }
HDIB LoadTIFFinDIB(LPSTR lpFileName) { TIFF *tif; unsigned long imageLength; unsigned long imageWidth; unsigned int BitsPerSample; unsigned long LineSize; unsigned int SamplePerPixel; unsigned long RowsPerStrip; int PhotometricInterpretation; long nrow; unsigned long row; char *buf; LPBITMAPINFOHEADER lpDIB; HDIB hDIB; char *lpBits; HGLOBAL hStrip; int i,l; int Align; tif = TIFFOpen(lpFileName, "r"); if (!tif) goto TiffOpenError; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imageWidth); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageLength); TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample); TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip); TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip); TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation); LineSize = TIFFScanlineSize(tif); //Number of byte in ine line SamplePerPixel = (int) (LineSize/imageWidth); //Align = Number of byte to add at the end of each line of the DIB Align = 4 - (LineSize % 4); if (Align == 4) Align = 0; //Create a new DIB hDIB = CreateDIB((DWORD) imageWidth, (DWORD) imageLength, (WORD) (BitsPerSample*SamplePerPixel)); lpDIB = (LPBITMAPINFOHEADER) GlobalLock(hDIB); if (!lpDIB) goto OutOfDIBMemory; if (lpDIB) lpBits = FindDIBBits((LPSTR) lpDIB); //In the tiff file the lines are save from up to down //In a DIB the lines must be save from down to up if (lpBits) { lpBits = FindDIBBits((LPSTR) lpDIB); lpBits+=((imageWidth*SamplePerPixel)+Align)*(imageLength-1); //now lpBits pointe on the bottom line hStrip = GlobalAlloc(GHND,TIFFStripSize(tif)); buf = GlobalLock(hStrip); if (!buf) goto OutOfBufMemory; //PhotometricInterpretation = 2 image is RGB //PhotometricInterpretation = 3 image have a color palette if (PhotometricInterpretation == 3) { uint16* red; uint16* green; uint16* blue; int16 i; LPBITMAPINFO lpbmi; int Palette16Bits; TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue); //Is the palette 16 or 8 bits ? if (checkcmap(1<<BitsPerSample, red, green, blue) == 16) Palette16Bits = TRUE; else Palette16Bits = FALSE; lpbmi = (LPBITMAPINFO)lpDIB; //load the palette in the DIB for (i = (1<<BitsPerSample)-1; i >= 0; i--) { if (Palette16Bits) { lpbmi->bmiColors[i].rgbRed =(BYTE) CVT(red[i]); lpbmi->bmiColors[i].rgbGreen = (BYTE) CVT(green[i]); lpbmi->bmiColors[i].rgbBlue = (BYTE) CVT(blue[i]); } else { lpbmi->bmiColors[i].rgbRed = (BYTE) red[i]; lpbmi->bmiColors[i].rgbGreen = (BYTE) green[i]; lpbmi->bmiColors[i].rgbBlue = (BYTE) blue[i]; } } } //read the tiff lines and save them in the DIB //with RGB mode, we have to change the order of the 3 samples RGB <=> BGR for (row = 0; row < imageLength; row += RowsPerStrip) { nrow = (row + RowsPerStrip > imageLength ? imageLength - row : RowsPerStrip); if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0), buf, nrow*LineSize)==-1) { goto TiffReadError; } else { for (l = 0; l < nrow; l++) { if (SamplePerPixel == 3) for (i=0; i< (int) (imageWidth); i++) { lpBits[i*SamplePerPixel+0]=buf[l*LineSize+i*Sample PerPixel+2]; lpBits[i*SamplePerPixel+1]=buf[l*LineSize+i*Sample PerPixel+1]; lpBits[i*SamplePerPixel+2]=buf[l*LineSize+i*Sample PerPixel+0]; } else memcpy(lpBits, &buf[(int) (l*LineSize)], (int) imageWidth*SamplePerPixel); lpBits-=imageWidth*SamplePerPixel+Align; } } } GlobalUnlock(hStrip); GlobalFree(hStrip); GlobalUnlock(hDIB); TIFFClose(tif); }
void USkeletalMesh::ConvertWedges(CSkelMeshLod &Lod, const TArray<FVector> &MeshPoints, const TArray<FMeshWedge> &MeshWedges, const TArray<FVertInfluence> &VertInfluences) { guard(USkeletalMesh::ConvertWedges); struct CVertInfo { int NumInfs; // may be higher than NUM_INFLUENCES int Bone[NUM_INFLUENCES]; float Weight[NUM_INFLUENCES]; }; int i, j; CVertInfo *Verts = new CVertInfo[MeshPoints.Num()]; memset(Verts, 0, MeshPoints.Num() * sizeof(CVertInfo)); // collect influences per vertex for (i = 0; i < VertInfluences.Num(); i++) { const FVertInfluence &Inf = VertInfluences[i]; CVertInfo &V = Verts[Inf.PointIndex]; int NumInfs = V.NumInfs++; int idx = NumInfs; if (NumInfs >= NUM_INFLUENCES) { // overflow // find smallest weight smaller than current float w = Inf.Weight; idx = -1; for (j = 0; j < NUM_INFLUENCES; j++) { if (V.Weight[j] < w) { w = V.Weight[j]; idx = j; // continue - may be other weight will be even smaller } } if (idx < 0) continue; // this weight is smaller than other } // add influence V.Bone[idx] = Inf.BoneIndex; V.Weight[idx] = Inf.Weight; } // normalize influences for (i = 0; i < MeshPoints.Num(); i++) { CVertInfo &V = Verts[i]; if (V.NumInfs == 0) { appPrintf("WARNING: Vertex %d has 0 influences\n", i); V.NumInfs = 1; V.Bone[0] = 0; V.Weight[0] = 1.0f; continue; } if (V.NumInfs <= NUM_INFLUENCES) continue; // no normalization is required float s = 0; for (j = 0; j < NUM_INFLUENCES; j++) // count sum s += V.Weight[j]; s = 1.0f / s; for (j = 0; j < NUM_INFLUENCES; j++) // adjust weights V.Weight[j] *= s; } // create vertices Lod.AllocateVerts(MeshWedges.Num()); for (i = 0; i < MeshWedges.Num(); i++) { const FMeshWedge &SW = MeshWedges[i]; CSkelMeshVertex &DW = Lod.Verts[i]; DW.Position = CVT(MeshPoints[SW.iVertex]); DW.UV = CVT(SW.TexUV); // DW.Normal and DW.Tangent are unset // setup Bone[] and Weight[] const CVertInfo &V = Verts[SW.iVertex]; unsigned PackedWeights = 0; for (j = 0; j < V.NumInfs; j++) { DW.Bone[j] = V.Bone[j]; PackedWeights |= appRound(V.Weight[j] * 255) << (j * 8); } DW.PackedWeights = PackedWeights; for (/* continue */; j < NUM_INFLUENCES; j++) // place end marker and zero weight { DW.Bone[j] = -1; } } delete Verts; unguard; }
void CVertMeshInstance::Draw(unsigned flags) { guard(CVertMeshInstance::Draw); if (!Sections.Num()) return; // empty mesh int i; // get 2 frames for interpolation int FrameNum1, FrameNum2; float frac; if (AnimIndex != INDEX_NONE) { const FMeshAnimSeq &A = pMesh->AnimSeqs[AnimIndex]; FrameNum1 = appFloor(AnimTime); FrameNum2 = FrameNum1 + 1; if (FrameNum2 >= A.NumFrames) FrameNum2 = 0; frac = AnimTime - FrameNum1; FrameNum1 += A.StartFrame; FrameNum2 += A.StartFrame; // clamp frame numbers (has mesh with wrong frame count in last animation: // UT1/BotPack/cdgunmainM; this animation is shown in UnrealEd as lerping to null size) if (FrameNum1 >= pMesh->FrameCount) FrameNum1 = pMesh->FrameCount-1; if (FrameNum2 >= pMesh->FrameCount) FrameNum2 = pMesh->FrameCount-1; } else { FrameNum1 = 0; FrameNum2 = 0; frac = 0; } int base1 = pMesh->VertexCount * FrameNum1; int base2 = pMesh->VertexCount * FrameNum2; float backLerp = 1 - frac; CVec3 Scale1, Scale2; Scale1 = Scale2 = CVT(pMesh->MeshScale); Scale1.Scale(backLerp); Scale2.Scale(frac); // compute deformed mesh const FMeshWedge *W = &pMesh->Wedges[0]; CVec3 *pVec = Verts; CVec3 *pNormal = Normals; for (i = 0; i < pMesh->Wedges.Num(); i++, pVec++, pNormal++, W++) { CVec3 tmp; #if 0 // path with no frame lerp // vertex const FMeshVert &V = pMesh->Verts[base1 + W->iVertex]; tmp[0] = V.X * pMesh->MeshScale.X; tmp[1] = V.Y * pMesh->MeshScale.Y; tmp[2] = V.Z * pMesh->MeshScale.Z; BaseTransform.TransformPoint(tmp, *pVec); // normal const FMeshNorm &N = pMesh->Normals[base1 + W->iVertex]; tmp[0] = (N.X - 512.0f) / 512; tmp[1] = (N.Y - 512.0f) / 512; tmp[2] = (N.Z - 512.0f) / 512; BaseTransform.axis.TransformVector(tmp, *pNormal); #else // vertex const FMeshVert &V1 = pMesh->Verts[base1 + W->iVertex]; const FMeshVert &V2 = pMesh->Verts[base2 + W->iVertex]; tmp[0] = V1.X * Scale1[0] + V2.X * Scale2[0]; tmp[1] = V1.Y * Scale1[1] + V2.Y * Scale2[1]; tmp[2] = V1.Z * Scale1[2] + V2.Z * Scale2[2]; BaseTransform.TransformPoint(tmp, *pVec); // normal const FMeshNorm &N1 = pMesh->Normals[base1 + W->iVertex]; const FMeshNorm &N2 = pMesh->Normals[base2 + W->iVertex]; tmp[0] = (N1.X * backLerp + N2.X * frac - 512.0f) / 512; tmp[1] = (N1.Y * backLerp + N2.Y * frac - 512.0f) / 512; tmp[2] = (N1.Z * backLerp + N2.Z * frac - 512.0f) / 512; BaseTransform.axis.TransformVector(tmp, *pNormal); #endif } #if 0 glBegin(GL_POINTS); for (i = 0; i < pMesh->Wedges.Num(); i++) { glVertex3fv(Verts[i].v); } glEnd(); return; #endif // draw mesh glEnable(GL_LIGHTING); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(CVec3), Verts); glNormalPointer(GL_FLOAT, sizeof(CVec3), Normals); glTexCoordPointer(2, GL_FLOAT, sizeof(FMeshWedge), &pMesh->Wedges[0].TexUV.U); for (i = 0; i < Sections.Num(); i++) { const CMeshSection &Sec = Sections[i]; if (!Sec.NumFaces) continue; SetMaterial(Sec.Material, i); glDrawElements(GL_TRIANGLES, Sec.NumFaces * 3, GL_UNSIGNED_SHORT, &Indices[Sec.FirstIndex]); } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisable(GL_LIGHTING); BindDefaultMaterial(true); // draw mesh normals if (flags & DF_SHOW_NORMALS) { glBegin(GL_LINES); glColor3f(0.5, 1, 0); for (i = 0; i < pMesh->Wedges.Num(); i++) { glVertex3fv(Verts[i].v); CVec3 tmp; VectorMA(Verts[i], 2, Normals[i], tmp); glVertex3fv(tmp.v); } glEnd(); } unguard; }