Selector::Selector(const sf::Texture& t) : m_texture (t), m_currentIndex (0), m_target (0.f) { sf::Vector2f texSize(t.getSize()); m_topButton.width = texSize.x / 2.f; m_topButton.height = texSize.y / 3.f; m_bottomButton = m_topButton; m_bottomButton.top = m_bottomButton.height * 2.f; m_vertices[0].texCoords.x = m_topButton.width; m_vertices[0].position.y = m_topButton.height; m_vertices[1].texCoords.x = texSize.x; m_vertices[1].position = { m_topButton.width, m_topButton.height }; m_vertices[2].texCoords = { texSize.x, m_topButton.height }; m_vertices[2].position = { m_topButton.width, m_topButton.height * 2.f }; m_vertices[3].texCoords = { m_topButton.width, m_topButton.height }; m_vertices[3].position.y = m_topButton.height * 2.f; m_vertices[5].texCoords.x = m_topButton.width; m_vertices[5].position.x = m_topButton.width; m_vertices[6].texCoords = { m_topButton.width, texSize.y }; m_vertices[6].position = m_vertices[6].texCoords; m_vertices[7].texCoords.y = texSize.y; m_vertices[7].position.y = texSize.y; m_localBounds.width = m_topButton.width; m_localBounds.height = texSize.y; }
void TransferFunctionPropertyDialog::exportTransferFunction() { InviwoFileDialog exportFileDialog(this, "Export transfer function", "transferfunction", InviwoApplication::getPtr()->getPath(InviwoApplication::PATH_TRANSFERFUNCTIONS) ); exportFileDialog.setAcceptMode(QFileDialog::AcceptSave); exportFileDialog.setFileMode(QFileDialog::AnyFile); exportFileDialog.addExtension("itf", "Inviwo Transfer Function"); exportFileDialog.addExtension("png", "Transfer Function Image"); exportFileDialog.addExtension("", "All files"); // this will add "All files (*)" if (exportFileDialog.exec()) { std::string file = exportFileDialog.selectedFiles().at(0).toLocal8Bit().constData(); std::string extension = filesystem::getFileExtension(file); FileExtension fileExt = exportFileDialog.getSelectedFileExtension(); if (fileExt.extension_.empty()) { // fall-back to standard inviwo TF format fileExt.extension_ = "itf"; } // check whether file extension matches the selected one if (fileExt.extension_ != extension) { file.append(fileExt.extension_); } if (fileExt.extension_ == "png") { TransferFunction &tf = tfProperty_->get(); const Layer* layer = tf.getData(); vec2 texSize(tf.getTextureSize(), 1); const vec4* readData = static_cast<const vec4*>(layer->getRepresentation<LayerRAM>()->getData()); Layer writeLayer(layer->getDimensions(), DataVec4UINT8::get()); glm::u8vec4* writeData = static_cast<glm::u8vec4*>(writeLayer.getEditableRepresentation<LayerRAM>()->getData()); for (std::size_t i=0; i<texSize.x * texSize.y; ++i) { for (int c=0; c<4; ++c) { writeData[i][c] = static_cast<glm::u8>(std::min(std::max(readData[i][c] * 255.0f, 0.0f), 255.0f)); } } auto writer = DataWriterFactory::getPtr()->getWriterForTypeAndExtension<Layer>(extension); if (writer) { try { writer->setOverwrite(true); writer->writeData(&writeLayer, file); } catch (DataWriterException const& e) { util::log(e.getContext(), e.getMessage(), LogLevel::Error); } } else { LogError("Error: Cound not find a writer for the specified extension and data type"); } } else if (fileExt.extension_ == "itf") { IvwSerializer serializer(file); tfProperty_->get().serialize(serializer); serializer.writeFile(); } } }
/** * Creates the textures and the display list needed for displaying * an OSD part. * Callback function for vo_draw_text(). */ static void create_osd_texture(int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride) { // initialize to 8 to avoid special-casing on alignment int sx = 8, sy = 8; GLint scale_type = scaled_osd ? GL_LINEAR : GL_NEAREST; if (w <= 0 || h <= 0 || stride < w) { mp_msg(MSGT_VO, MSGL_V, "Invalid dimensions OSD for part!\n"); return; } texSize(w, h, &sx, &sy); if (osdtexCnt >= MAX_OSD_PARTS) { mp_msg(MSGT_VO, MSGL_ERR, "Too many OSD parts, contact the developers!\n"); return; } // create Textures for OSD part mpglGenTextures(1, &osdtex[osdtexCnt]); mpglBindTexture(gl_target, osdtex[osdtexCnt]); glCreateClearTex(gl_target, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, scale_type, sx, sy, 0); glUploadTex(gl_target, GL_LUMINANCE, GL_UNSIGNED_BYTE, src, stride, 0, 0, w, h, 0); #ifndef FAST_OSD mpglGenTextures(1, &osdatex[osdtexCnt]); mpglBindTexture(gl_target, osdatex[osdtexCnt]); glCreateClearTex(gl_target, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, scale_type, sx, sy, 0); { int i; char *tmp = malloc(stride * h); // convert alpha from weird MPlayer scale. // in-place is not possible since it is reused for future OSDs for (i = h * stride - 1; i >= 0; i--) tmp[i] = -srca[i]; glUploadTex(gl_target, GL_ALPHA, GL_UNSIGNED_BYTE, tmp, stride, 0, 0, w, h, 0); free(tmp); } #endif mpglBindTexture(gl_target, 0); // Create a list for rendering this OSD part #ifndef FAST_OSD osdaDispList[osdtexCnt] = mpglGenLists(1); mpglNewList(osdaDispList[osdtexCnt], GL_COMPILE); // render alpha mpglBindTexture(gl_target, osdatex[osdtexCnt]); glDrawTex(x0, y0, w, h, 0, 0, w, h, sx, sy, use_rectangle == 1, 0, 0); mpglEndList(); #endif osdDispList[osdtexCnt] = mpglGenLists(1); mpglNewList(osdDispList[osdtexCnt], GL_COMPILE); // render OSD mpglBindTexture(gl_target, osdtex[osdtexCnt]); glDrawTex(x0, y0, w, h, 0, 0, w, h, sx, sy, use_rectangle == 1, 0, 0); mpglEndList(); osdtexCnt++; }
/** * \brief Initialize a (new or reused) OpenGL context. * set global gl-related variables to their default values */ static int initGl(uint32_t d_width, uint32_t d_height) { GLint scale_type = get_scale_type(0); autodetectGlExtensions(); gl_target = use_rectangle == 1 ? GL_TEXTURE_RECTANGLE : GL_TEXTURE_2D; yuvconvtype = SET_YUV_CONVERSION(use_yuv) | SET_YUV_LUM_SCALER(lscale) | SET_YUV_CHROM_SCALER(cscale); texSize(image_width, image_height, &texture_width, &texture_height); mpglDisable(GL_BLEND); mpglDisable(GL_DEPTH_TEST); mpglDepthMask(GL_FALSE); mpglDisable(GL_CULL_FACE); mpglEnable(gl_target); mpglDrawBuffer(vo_doublebuffering?GL_BACK:GL_FRONT); mpglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); mp_msg(MSGT_VO, MSGL_V, "[gl] Creating %dx%d texture...\n", texture_width, texture_height); glCreateClearTex(gl_target, gl_texfmt, gl_format, gl_type, scale_type, texture_width, texture_height, 0); if (mipmap_gen) mpglTexParameteri(gl_target, GL_GENERATE_MIPMAP, GL_TRUE); if (is_yuv) { int i; int xs, ys; scale_type = get_scale_type(1); mp_get_chroma_shift(image_format, &xs, &ys); mpglGenTextures(21, default_texs); default_texs[21] = 0; for (i = 0; i < 7; i++) { mpglActiveTexture(GL_TEXTURE1 + i); mpglBindTexture(GL_TEXTURE_2D, default_texs[i]); mpglBindTexture(GL_TEXTURE_RECTANGLE, default_texs[i + 7]); mpglBindTexture(GL_TEXTURE_3D, default_texs[i + 14]); } mpglActiveTexture(GL_TEXTURE1); glCreateClearTex(gl_target, gl_texfmt, gl_format, gl_type, scale_type, texture_width >> xs, texture_height >> ys, 128); if (mipmap_gen) mpglTexParameteri(gl_target, GL_GENERATE_MIPMAP, GL_TRUE); mpglActiveTexture(GL_TEXTURE2); glCreateClearTex(gl_target, gl_texfmt, gl_format, gl_type, scale_type, texture_width >> xs, texture_height >> ys, 128); if (mipmap_gen) mpglTexParameteri(gl_target, GL_GENERATE_MIPMAP, GL_TRUE); mpglActiveTexture(GL_TEXTURE0); mpglBindTexture(gl_target, 0); } if (is_yuv || custom_prog) { if ((MASK_NOT_COMBINERS & (1 << use_yuv)) || custom_prog) { if (!mpglGenPrograms || !mpglBindProgram) { mp_msg(MSGT_VO, MSGL_ERR, "[gl] fragment program functions missing!\n"); } else { mpglGenPrograms(1, &fragprog); mpglBindProgram(GL_FRAGMENT_PROGRAM, fragprog); } } update_yuvconv(); } resize(d_width, d_height); mpglClearColor( 0.0f,0.0f,0.0f,0.0f ); mpglClear( GL_COLOR_BUFFER_BIT ); if (mpglSwapInterval && swap_interval >= 0) mpglSwapInterval(swap_interval); return 1; }
/** * \brief construct display list from ass image list * \param img image list to create OSD from. * A value of NULL has the same effect as clearEOSD() */ static void genEOSD(struct mp_eosd_image_list *imgs) { int sx, sy; int tinytexcur = 0; int smalltexcur = 0; GLuint *curtex; GLint scale_type = scaled_osd ? GL_LINEAR : GL_NEAREST; struct mp_eosd_image *img = eosd_image_first(imgs); struct mp_eosd_image *i; if (imgs->changed == 0) // there are elements, but they are unchanged return; if (img && imgs->changed == 1) // there are elements, but they just moved goto skip_upload; clearEOSD(); if (!img) return; if (!largeeosdtex[0]) { mpglGenTextures(2, largeeosdtex); mpglBindTexture(gl_target, largeeosdtex[0]); glCreateClearTex(gl_target, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, scale_type, LARGE_EOSD_TEX_SIZE, LARGE_EOSD_TEX_SIZE, 0); mpglBindTexture(gl_target, largeeosdtex[1]); glCreateClearTex(gl_target, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, scale_type, LARGE_EOSD_TEX_SIZE, LARGE_EOSD_TEX_SIZE, 0); } for (i = img; i; i = eosd_image_next(imgs)) { if (i->w <= 0 || i->h <= 0 || i->stride < i->w) continue; if (is_tinytex(i, tinytexcur)) tinytexcur++; else if (is_smalltex(i, smalltexcur)) smalltexcur++; else eosdtexCnt++; } mp_msg(MSGT_VO, MSGL_DBG2, "EOSD counts (tiny, small, all): %i, %i, %i\n", tinytexcur, smalltexcur, eosdtexCnt); if (eosdtexCnt) { eosdtex = calloc(eosdtexCnt, sizeof(GLuint)); mpglGenTextures(eosdtexCnt, eosdtex); } tinytexcur = smalltexcur = 0; for (i = eosd_image_first(imgs), curtex = eosdtex; i; i = eosd_image_next(imgs)) { int x = 0, y = 0; if (i->w <= 0 || i->h <= 0 || i->stride < i->w) { mp_msg(MSGT_VO, MSGL_V, "Invalid dimensions OSD for part!\n"); continue; } if (is_tinytex(i, tinytexcur)) { tinytex_pos(tinytexcur, &x, &y); mpglBindTexture(gl_target, largeeosdtex[0]); tinytexcur++; } else if (is_smalltex(i, smalltexcur)) { smalltex_pos(smalltexcur, &x, &y); mpglBindTexture(gl_target, largeeosdtex[1]); smalltexcur++; } else { texSize(i->w, i->h, &sx, &sy); mpglBindTexture(gl_target, *curtex++); glCreateClearTex(gl_target, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, scale_type, sx, sy, 0); } glUploadTex(gl_target, GL_ALPHA, GL_UNSIGNED_BYTE, i->bitmap, i->stride, x, y, i->w, i->h, 0); } eosdDispList = mpglGenLists(1); skip_upload: mpglNewList(eosdDispList, GL_COMPILE); tinytexcur = smalltexcur = 0; for (i = eosd_image_first(imgs), curtex = eosdtex; i; i = eosd_image_next(imgs)) { int x = 0, y = 0; if (i->w <= 0 || i->h <= 0 || i->stride < i->w) continue; mpglColor4ub(i->color >> 24, (i->color >> 16) & 0xff, (i->color >> 8) & 0xff, 255 - (i->color & 0xff)); if (is_tinytex(i, tinytexcur)) { tinytex_pos(tinytexcur, &x, &y); sx = sy = LARGE_EOSD_TEX_SIZE; mpglBindTexture(gl_target, largeeosdtex[0]); tinytexcur++; } else if (is_smalltex(i, smalltexcur)) { smalltex_pos(smalltexcur, &x, &y); sx = sy = LARGE_EOSD_TEX_SIZE; mpglBindTexture(gl_target, largeeosdtex[1]); smalltexcur++; } else { texSize(i->w, i->h, &sx, &sy); mpglBindTexture(gl_target, *curtex++); } glDrawTex(i->dst_x, i->dst_y, i->w, i->h, x, y, i->w, i->h, sx, sy, use_rectangle == 1, 0, 0); } mpglEndList(); mpglBindTexture(gl_target, 0); }
void TSLastDetail::_update() { // We're gonna render... make sure we can. bool sceneBegun = GFX->canCurrentlyRender(); if ( !sceneBegun ) GFX->beginScene(); _validateDim(); Vector<GBitmap*> bitmaps; Vector<GBitmap*> normalmaps; // We need to create our own instance to render with. TSShapeInstance *shape = new TSShapeInstance( mShape, true ); // Animate the shape once. shape->animate( mDl ); // So we don't have to change it everywhere. const GFXFormat format = GFXFormatR8G8B8A8; S32 imposterCount = ( ((2*mNumPolarSteps) + 1 ) * mNumEquatorSteps ) + ( mIncludePoles ? 2 : 0 ); // Figure out the optimal texture size. Point2I texSize( smMaxTexSize, smMaxTexSize ); while ( true ) { Point2I halfSize( texSize.x / 2, texSize.y / 2 ); U32 count = ( halfSize.x / mDim ) * ( halfSize.y / mDim ); if ( count < imposterCount ) { // Try half of the height. count = ( texSize.x / mDim ) * ( halfSize.y / mDim ); if ( count >= imposterCount ) texSize.y = halfSize.y; break; } texSize = halfSize; } GBitmap *imposter = NULL; GBitmap *normalmap = NULL; GBitmap destBmp( texSize.x, texSize.y, true, format ); GBitmap destNormal( texSize.x, texSize.y, true, format ); U32 mipLevels = destBmp.getNumMipLevels(); ImposterCapture *imposterCap = new ImposterCapture(); F32 equatorStepSize = M_2PI_F / (F32)mNumEquatorSteps; static const MatrixF topXfm( EulerF( -M_PI_F / 2.0f, 0, 0 ) ); static const MatrixF bottomXfm( EulerF( M_PI_F / 2.0f, 0, 0 ) ); MatrixF angMat; F32 polarStepSize = 0.0f; if ( mNumPolarSteps > 0 ) polarStepSize = -( 0.5f * M_PI_F - mDegToRad( mPolarAngle ) ) / (F32)mNumPolarSteps; PROFILE_START(TSLastDetail_snapshots); S32 currDim = mDim; for ( S32 mip = 0; mip < mipLevels; mip++ ) { if ( currDim < 1 ) currDim = 1; dMemset( destBmp.getWritableBits(mip), 0, destBmp.getWidth(mip) * destBmp.getHeight(mip) * GFXFormat_getByteSize( format ) ); dMemset( destNormal.getWritableBits(mip), 0, destNormal.getWidth(mip) * destNormal.getHeight(mip) * GFXFormat_getByteSize( format ) ); bitmaps.clear(); normalmaps.clear(); F32 rotX = 0.0f; if ( mNumPolarSteps > 0 ) rotX = -( mDegToRad( mPolarAngle ) - 0.5f * M_PI_F ); // We capture the images in a particular order which must // match the order expected by the imposter renderer. imposterCap->begin( shape, mDl, currDim, mRadius, mCenter ); for ( U32 j=0; j < (2 * mNumPolarSteps + 1); j++ ) { F32 rotZ = -M_PI_F / 2.0f; for ( U32 k=0; k < mNumEquatorSteps; k++ ) { angMat.mul( MatrixF( EulerF( rotX, 0, 0 ) ), MatrixF( EulerF( 0, 0, rotZ ) ) ); imposterCap->capture( angMat, &imposter, &normalmap ); bitmaps.push_back( imposter ); normalmaps.push_back( normalmap ); rotZ += equatorStepSize; } rotX += polarStepSize; if ( mIncludePoles ) { imposterCap->capture( topXfm, &imposter, &normalmap ); bitmaps.push_back(imposter); normalmaps.push_back( normalmap ); imposterCap->capture( bottomXfm, &imposter, &normalmap ); bitmaps.push_back( imposter ); normalmaps.push_back( normalmap ); } } imposterCap->end(); Point2I texSize( destBmp.getWidth(mip), destBmp.getHeight(mip) ); // Ok... pack in bitmaps till we run out. for ( S32 y=0; y+currDim <= texSize.y; ) { for ( S32 x=0; x+currDim <= texSize.x; ) { // Copy the next bitmap to the dest texture. GBitmap* bmp = bitmaps.first(); bitmaps.pop_front(); destBmp.copyRect( bmp, RectI( 0, 0, currDim, currDim ), Point2I( x, y ), 0, mip ); delete bmp; // Copy the next normal to the dest texture. GBitmap* normalmap = normalmaps.first(); normalmaps.pop_front(); destNormal.copyRect( normalmap, RectI( 0, 0, currDim, currDim ), Point2I( x, y ), 0, mip ); delete normalmap; // Did we finish? if ( bitmaps.empty() ) break; x += currDim; } // Did we finish? if ( bitmaps.empty() ) break; y += currDim; } // Next mip... currDim /= 2; } PROFILE_END(); // TSLastDetail_snapshots delete imposterCap; delete shape; // Should we dump the images? if ( Con::getBoolVariable( "$TSLastDetail::dumpImposters", false ) ) { String imposterPath = mCachePath + ".imposter.png"; String normalsPath = mCachePath + ".imposter_normals.png"; FileStream stream; if ( stream.open( imposterPath, Torque::FS::File::Write ) ) destBmp.writeBitmap( "png", stream ); stream.close(); if ( stream.open( normalsPath, Torque::FS::File::Write ) ) destNormal.writeBitmap( "png", stream ); stream.close(); } // DEBUG: Some code to force usage of a test image. //GBitmap* tempMap = GBitmap::load( "./forest/data/test1234.png" ); //tempMap->extrudeMipLevels(); //mTexture.set( tempMap, &GFXDefaultStaticDiffuseProfile, false ); //delete tempMap; DDSFile *ddsDest = DDSFile::createDDSFileFromGBitmap( &destBmp ); DDSUtil::squishDDS( ddsDest, GFXFormatDXT3 ); DDSFile *ddsNormals = DDSFile::createDDSFileFromGBitmap( &destNormal ); DDSUtil::squishDDS( ddsNormals, GFXFormatDXT5 ); // Finally save the imposters to disk. FileStream fs; if ( fs.open( _getDiffuseMapPath(), Torque::FS::File::Write ) ) { ddsDest->write( fs ); fs.close(); } if ( fs.open( _getNormalMapPath(), Torque::FS::File::Write ) ) { ddsNormals->write( fs ); fs.close(); } delete ddsDest; delete ddsNormals; // If we did a begin then end it now. if ( !sceneBegun ) GFX->endScene(); }
void TSLastDetail::update( bool forceUpdate ) { // This should never be called on a dedicated server or // anywhere else where we don't have a GFX device! AssertFatal( GFXDevice::devicePresent(), "TSLastDetail::update() - Cannot update without a GFX device!" ); // Clear the materialfirst. SAFE_DELETE( mMatInstance ); if ( mMaterial ) { mMaterial->deleteObject(); mMaterial = NULL; } // Make sure imposter textures have been flushed (and not just queued for deletion) TEXMGR->cleanupCache(); // Get the real path to the source shape for doing modified time // comparisons... this might be different if the DAEs have been // deleted from the install. String shapeFile( mCachePath ); if ( !Platform::isFile( shapeFile ) ) { Torque::Path path(shapeFile); path.setExtension("cached.dts"); shapeFile = path.getFullPath(); if ( !Platform::isFile( shapeFile ) ) { Con::errorf( "TSLastDetail::update - '%s' could not be found!", mCachePath.c_str() ); return; } } // Do we need to update the imposter? const String diffuseMapPath = _getDiffuseMapPath(); if ( forceUpdate || Platform::compareModifiedTimes( diffuseMapPath, shapeFile ) <= 0 ) _update(); // If the time check fails now then the update must have not worked. if ( Platform::compareModifiedTimes( diffuseMapPath, shapeFile ) < 0 ) { Con::errorf( "TSLastDetail::update - Failed to create imposters for '%s'!", mCachePath.c_str() ); return; } // Figure out what our vertex format will be. // // If we're on SM 3.0 we can do multiple vertex streams // and the performance win is big as we send 3x less data // on each imposter instance. // // The problem is SM 2.0 won't do this, so we need to // support fallback to regular single stream imposters. // //mImposterVertDecl.copy( *getGFXVertexFormat<ImposterCorner>() ); //mImposterVertDecl.append( *getGFXVertexFormat<ImposterState>(), 1 ); //mImposterVertDecl.getDecl(); mImposterVertDecl.clear(); mImposterVertDecl.copy( *getGFXVertexFormat<ImposterState>() ); // Setup the material for this imposter. mMaterial = MATMGR->allocateAndRegister( String::EmptyString ); mMaterial->mAutoGenerated = true; mMaterial->mDiffuseMapFilename[0] = diffuseMapPath; mMaterial->mNormalMapFilename[0] = _getNormalMapPath(); mMaterial->mImposterLimits.set( (mNumPolarSteps * 2) + 1, mNumEquatorSteps, mPolarAngle, mIncludePoles ); mMaterial->mTranslucent = true; mMaterial->mTranslucentBlendOp = Material::None; mMaterial->mTranslucentZWrite = true; mMaterial->mDoubleSided = true; mMaterial->mAlphaTest = true; mMaterial->mAlphaRef = 84; // Create the material instance. FeatureSet features = MATMGR->getDefaultFeatures(); features.addFeature( MFT_ImposterVert ); mMatInstance = mMaterial->createMatInstance(); if ( !mMatInstance->init( features, &mImposterVertDecl ) ) { delete mMatInstance; mMatInstance = NULL; } // Get the diffuse texture and from its size and // the imposter dimensions we can generate the UVs. GFXTexHandle diffuseTex( diffuseMapPath, &GFXDefaultStaticDiffuseProfile, String::EmptyString ); Point2I texSize( diffuseTex->getWidth(), diffuseTex->getHeight() ); _validateDim(); S32 downscaledDim = mDim >> GFXTextureManager::getTextureDownscalePower(&GFXDefaultStaticDiffuseProfile); // Ok... pack in bitmaps till we run out. Vector<RectF> imposterUVs; for ( S32 y=0; y+downscaledDim <= texSize.y; ) { for ( S32 x=0; x+downscaledDim <= texSize.x; ) { // Store the uv for later lookup. RectF info; info.point.set( (F32)x / (F32)texSize.x, (F32)y / (F32)texSize.y ); info.extent.set( (F32)downscaledDim / (F32)texSize.x, (F32)downscaledDim / (F32)texSize.y ); imposterUVs.push_back( info ); x += downscaledDim; } y += downscaledDim; } AssertFatal( imposterUVs.size() != 0, "hey" ); mMaterial->mImposterUVs = imposterUVs; }
//-------------------------------------------------------------- void ofApp::setup() { ofDirectory dir; ofVideoPlayer player; int edge = 2; ofxXmlSettings settings; settings.loadFile("settings.xml"); ofVec2f movieSize(settings.getValue("movieSize:width", 128) + edge, settings.getValue("movieSize:height", 128) + edge); ofVec2f texSize(settings.getValue("texSize:width", 1024), settings.getValue("texSize:height", 1024)); float duration = settings.getValue("duration", 1.0); float fps = settings.getValue("fps", 1.0); int numFrames = duration * fps; int numMovies = dir.listDir("movies"); int totalFrames = numFrames * numMovies; float movieRatio = movieSize.x / movieSize.y; float texArea = texSize.x * texSize.y; float fitArea = texArea / (float)totalFrames; float fitHeight = sqrt(fitArea/movieRatio); float fitWidth = fitArea/fitHeight; ofVec2f fitSize(fitWidth, fitHeight); ofVec2f numUnits(ceil(texSize.x / fitSize.x), ceil(texSize.y / fitSize.y)); ofVec2f size = texSize / numUnits; ofVec2f scale = movieSize / size; ofFile::removeFile("sprite.js"); ofstream js; js.open (ofToDataPath("sprite.js").c_str(), std::ios::out | std::ios::app); js << "var sprite={coordinates:["; ofFbo fbo; fbo.allocate(texSize.x, texSize.y); fbo.begin(); ofClear(0, 0, 0, 0); fbo.end(); float column = -1; float row = -1; int frameIndex = 0; for (float i = 0; i < numMovies; i++) { player.loadMovie(dir.getPath(i)); cout << dir.getPath(i) << endl; int playerNumFrames = player.getTotalNumFrames(); float offset = (float)playerNumFrames / (float)numFrames; js << "["; for (float j = 0; j < numFrames; j++) { column = frameIndex % (int)numUnits.x; if(column == 0) row++; js << "\"-" << (column * movieSize.x) << "px -" << (row * movieSize.y) << "px\""; if(j < numFrames-1) js << ","; player.setFrame(j * offset+1); player.update(); fbo.begin(); player.draw(floor(column * size.x), floor(row * size.y), ceil(size.x), ceil(size.y)); fbo.end(); frameIndex++; } js << "]"; if(i < numMovies-1) js << ","; } js << "]"; js << ",duration:" << duration; js << ",image:\"sprite.png\""; js << ",numFrames:" << numFrames; js << ",numMovies:" << numMovies; js << ",width:" << movieSize.x - edge; js << ",height:" << movieSize.y - edge; js << ",backgroundSize:\"" << (texSize.x * scale.x) << "px " << (texSize.y * scale.y)<< "px\""; js << "};"; js.close(); ofPixels pixels; pixels.allocate(texSize.x, texSize.y, 4); fbo.readToPixels(pixels); ofSaveImage(pixels, "sprite.png"); ofExit(0); }
void XRandBG::update(float steptime) { if (!m_isInited) return; float curTime = steptime * 0.001f; //出生的处理 //m_bornTime -= curTime; //if (m_bornTime <= 0.0f) //{ // born(); // m_bornTime = XRand::randomf(0.75f, 1.25f) * m_avgBornTimer; //} //状态更新 //方案1: //for (int i = 0; i < m_usedObjs.size(); ++i) //{ // if (!m_usedObjs[i]->update(curTime)) continue; // m_freeObjs.push_back(m_usedObjs[i]); // m_usedObjs.erase(m_usedObjs.begin() + i); // --i; // born(); //} //方案2: int deadSum = 0; for (auto it = m_usedObjs.begin(); it != m_usedObjs.end();) { if (!(*it)->update(curTime)) { ++it; continue; } m_freeObjs.push_back(*it); it = m_usedObjs.erase(it); ++deadSum; } for (int i = 0; i < deadSum; ++i) {//不分开处理会crash born(); } //显示 XVec2 texSize(m_tex.getOpWidth(), m_tex.getOpHeight()); m_fbo.useFBO(); XEG.clearScreen(XFColor::black); //XGL::setBlendAlpha(); XGL::setBlendAdd(); XVec2 s, pos; #ifdef WITH_DRAW_OP glActiveTexture(GL_TEXTURE0); XGL::EnableTexture2D(); XGL::BindTexture2D(m_tex.getTexGLID()); glBegin(GL_QUADS); for (auto it = m_usedObjs.begin(); it != m_usedObjs.end(); ++it) { s = texSize * (*it)->m_scale * 0.5f; pos = (*it)->m_pos; glColor4fv(XFColor(1.0f, (*it)->m_alpha)); glTexCoord2fv(XVec2::zero); glVertex2fv(pos - s); glTexCoord2fv(XVec2::zeroOne); glVertex2f(pos.x - s.x, pos.y + s.y); glTexCoord2fv(XVec2::one); glVertex2fv(pos + s); glTexCoord2fv(XVec2::oneZero); glVertex2f(pos.x + s.x, pos.y - s.y); } glEnd(); #else for (auto it = m_usedObjs.begin(); it != m_usedObjs.end(); ++it) { tmpSize = texSize * (*it)->m_scale; XRender::drawBlankPlane((*it)->m_pos - tmpSize * 0.5f, tmpSize, m_tex.getTexGLID(), nullptr, XFColor(1.0f, (*it)->m_alpha)); } #endif glReadPixels(0, 0, m_w, m_h, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_buff.getBuffer()); m_fbo.removeFBO(); }