JNIEXPORT void JNICALL Java_org_cocos2dx_lib_CCImage_1richlabel_nativeGetSpriteFrameInfo
  (JNIEnv * env, jclass clazz, jstring jPlist, jstring jAtlas, jstring jImageName, jobject jFrame) {
	// get c string
	const char* plist = (const char*)env->GetStringUTFChars(jPlist, NULL);
	const char* atlas = (const char*)env->GetStringUTFChars(jAtlas, NULL);
	const char* imageName = (const char*)env->GetStringUTFChars(jImageName, NULL);

	// get sprite frame
	CLBitmapDC& bitmapDC = CLBitmapDC::sharedCLBitmapDC();
	CCSpriteFrameCache* fc = CCSpriteFrameCache::sharedSpriteFrameCache();
	if(!fc->spriteFrameByName(imageName)) {
		if(bitmapDC.m_decryptFunc) {
			// load encryptd data
			unsigned long len;
			char* data = (char*)CCFileUtils::sharedFileUtils()->getFileData(atlas, "rb", &len);

			// create texture
			int decLen;
			const char* dec = (*bitmapDC.m_decryptFunc)(data, (int)len, &decLen);
			CCImage* image = new CCImage();
			image->initWithImageData((void*)dec, decLen);
			image->autorelease();
			CCTexture2D* tex = CCTextureCache::sharedTextureCache()->addUIImage(image, atlas);

			// add
			fc->addSpriteFramesWithFile(plist, tex);

			// free
			if(data != dec)
				free((void*)dec);
			free(data);
		} else {
			fc->addSpriteFramesWithFile(plist, atlas);
		}
	}
	CCSpriteFrame* frame = fc->spriteFrameByName(imageName);

	// get java frame info
	jclass frameClass = env->FindClass("org/cocos2dx/lib/CCImage_richlabel$AtlasFrame");
	jfieldID fid_x = env->GetFieldID(frameClass, "x", "I");
	jfieldID fid_y = env->GetFieldID(frameClass, "y", "I");
	jfieldID fid_w = env->GetFieldID(frameClass, "w", "I");
	jfieldID fid_h = env->GetFieldID(frameClass, "h", "I");
	jfieldID fid_offsetX = env->GetFieldID(frameClass, "offsetX", "I");
	jfieldID fid_offsetY = env->GetFieldID(frameClass, "offsetY", "I");
	jfieldID fid_sourceWidth = env->GetFieldID(frameClass, "sourceWidth", "I");
	jfieldID fid_sourceHeight = env->GetFieldID(frameClass, "sourceHeight", "I");
	jfieldID fid_rotated = env->GetFieldID(frameClass, "rotated", "Z");

	// copy frame info to java object
	const CCSize& sourceSize = frame->getOriginalSizeInPixels();
	bool rotated = frame->isRotated();
	const CCRect& frameRect = frame->getRectInPixels();
	const CCPoint& offset = frame->getOffsetInPixels();
	env->SetIntField(jFrame, fid_x, (int)frameRect.origin.x);
	env->SetIntField(jFrame, fid_y, (int)frameRect.origin.y);
	env->SetIntField(jFrame, fid_w, (int)frameRect.size.width);
	env->SetIntField(jFrame, fid_h, (int)frameRect.size.height);
	env->SetIntField(jFrame, fid_offsetX, (int)offset.x);
	env->SetIntField(jFrame, fid_offsetY, (int)offset.y);
	env->SetIntField(jFrame, fid_sourceWidth, (int)sourceSize.width);
	env->SetIntField(jFrame, fid_sourceHeight, (int)sourceSize.height);
	env->SetBooleanField(jFrame, fid_rotated, rotated);

	// release
	env->DeleteLocalRef(frameClass);
	env->ReleaseStringUTFChars(jPlist, plist);
	env->ReleaseStringUTFChars(jAtlas, atlas);
	env->ReleaseStringUTFChars(jImageName, imageName);
}
//the frames should have the same size in texture so shouldn't trim the frame
//I wish this limit will be removed in next moment
void CCParticleSystemFrameQuad::setTextureWithFrames(CCTexture2D* texture, CCArray* frames)
{
    // Only update the texture if is different from the current one
    if( !m_pTexture || texture->getName() != m_pTexture->getName() )
    {
        CCParticleSystem::setTexture(texture);
    }

	clearFrameSetting();
	unsigned int totalFrames = frames->count();
	m_pFrameQuads = new float *[totalFrames];
	for(unsigned int i=0; i<totalFrames;i++){
		CCSpriteFrame *frame = dynamic_cast<CCSpriteFrame*>(frames->objectAtIndex(i));
		if(frame==NULL || frame->getTexture()->getName()!= m_pTexture->getName())
			continue;
		
		CCRect rect = frame->getRect();

		float* m_sQuad = new float[4];
		m_pFrameQuads[m_uTotalFrames] = m_sQuad;
		m_uTotalFrames++;

		float atlasWidth = (float)m_pTexture->getPixelsWide();
		float atlasHeight = (float)m_pTexture->getPixelsHigh();

		float left, right, top, bottom;

		if (frame->isRotated())
		{
	#if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
			left    = (2*rect.origin.x+1)/(2*atlasWidth);
			right    = left+(rect.size.height*2-2)/(2*atlasWidth);
			top        = (2*rect.origin.y+1)/(2*atlasHeight);
			bottom    = top+(rect.size.width*2-2)/(2*atlasHeight);
	#else
			left    = rect.origin.x/atlasWidth;
			right    = (rect.origin.x+rect.size.height) / atlasWidth;
			top        = rect.origin.y/atlasHeight;
			bottom    = (rect.origin.y+rect.size.width) / atlasHeight;
	#endif // CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
		}
		else
		{
	#if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
			left    = (2*rect.origin.x+1)/(2*atlasWidth);
			right    = left + (rect.size.width*2-2)/(2*atlasWidth);
			top        = (2*rect.origin.y+1)/(2*atlasHeight);
			bottom    = top + (rect.size.height*2-2)/(2*atlasHeight);
	#else
			left    = rect.origin.x/atlasWidth;
			right    = (rect.origin.x + rect.size.width) / atlasWidth;
			top        = rect.origin.y/atlasHeight;
			bottom    = (rect.origin.y + rect.size.height) / atlasHeight;
	#endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
		}
		m_sQuad[0] = left;
		m_sQuad[1] = right;
		m_sQuad[2] = top;
		m_sQuad[3] = bottom;
	}

    GLfloat wide = (GLfloat)m_pTexture->getPixelsWide();
    GLfloat high = (GLfloat)m_pTexture->getPixelsHigh();

    ccV3F_C4B_T2F_Quad *quads = NULL;
    unsigned int start = 0, end = 0;
    if (m_pBatchNode)
    {
        quads = m_pBatchNode->getTextureAtlas()->getQuads();
        start = m_uAtlasIndex;
        end = m_uAtlasIndex + m_uTotalParticles;
    }
    else
    {
        quads = m_pQuads;
        start = 0;
        end = m_uTotalParticles;
    }

    for(unsigned int i=start; i<end; i++) 
    {
		int fid = rand()%m_uTotalFrames;
		float* m_sQuad = m_pFrameQuads[fid];
        // bottom-left vertex:
        quads[i].bl.texCoords.u = m_sQuad[0];
        quads[i].bl.texCoords.v = m_sQuad[3];
        // bottom-right vertex:
        quads[i].br.texCoords.u = m_sQuad[1];
        quads[i].br.texCoords.v = m_sQuad[3];
        // top-left vertex:
        quads[i].tl.texCoords.u = m_sQuad[0];
        quads[i].tl.texCoords.v = m_sQuad[2];
        // top-right vertex:
        quads[i].tr.texCoords.u = m_sQuad[1];
        quads[i].tr.texCoords.v = m_sQuad[2];
    }
}