コード例 #1
0
void mesh_filter::StereoCameraModel::Parameters::setFilterParameters (GLRenderer& renderer) const
{
  glUniform1f (glGetUniformLocation (renderer.getProgramID (), "near"), near_clipping_plane_distance_);
  glUniform1f (glGetUniformLocation (renderer.getProgramID (), "far"), far_clipping_plane_distance_);

  renderer.setClippingRange (near_clipping_plane_distance_, far_clipping_plane_distance_);
  renderer.setBufferSize (width_, height_);
  renderer.setCameraParameters (fx_, fy_, cx_, cy_);
}
コード例 #2
0
void mesh_filter::StereoCameraModel::Parameters::setRenderParameters (GLRenderer& renderer) const
{
  renderer.setClippingRange (near_clipping_plane_distance_, far_clipping_plane_distance_);
  renderer.setBufferSize (width_, height_);
  renderer.setCameraParameters (fx_, fy_, cx_, cy_);
  //GLuint padding_coefficients_id = glGetUniformLocation (renderer.getProgramID (), "padding_coefficients");

//  // set device dependent padding coefficients
//  glUniform3f (padding_coefficients_id, padding_coefficients_1_ * padding_scale_,
//                                        padding_coefficients_2_ * padding_scale_,
//                                        padding_coefficients_3_ * padding_scale_  + padding_offset_ );
}
コード例 #3
0
//-----------------------------------------------------------------------------
void			RenderingContext::Draw(Shader& shader, GLRenderer& gl_renderer)
{
	__GL_CALL(glUseProgram(shader.GetProgram()))
	
	shader.SetUniforms(*this);
	gl_renderer.Draw(shader, *this);
}
コード例 #4
0
void	GL_LoadStaticScene()
{
	
	for(unsigned int wo=0;wo<staticObjectCount;wo++) {
		GL_AddModelToLists(&staticObjectPool[wo], true);
	}
	
	renderer.staticsRebuild();
}
コード例 #5
0
void	GL_AddLight(residx_t shader, sceneobj_t *obj, bool bStatic)
{
	worldLight_t *l = &worldlights[lightCount++];
	memset(l, 0, sizeof(worldLight_t));
	M_CopyVec3(obj->color, l->color);
	//M_CopyVec3(obj->pos, l.origin);
	l->falloff = obj->scale;
	
	renderer.addLight(l, obj, shader, bStatic);
}
コード例 #6
0
ファイル: shader_fireball.cpp プロジェクト: ronj/invent
void shader_fireball( GLWindow& window, GLRenderer& renderer ) {

  auto camera = PerspectiveCamera::create(
    40, (float)renderer.width() / renderer.height(), 1, 3000
  );
  camera->position().z = 4;

  auto scene = Scene::create();

  float time = 1;

  auto material = ShaderMaterial::create(
    vertexShader,
    fragmentShader,
    Uniforms().add("time",  Uniform( THREE::f, time ))
              .add("scale", Uniform( THREE::f, 1.5f ))
  );

  // Geometries
  auto mesh = Mesh::create( SphereGeometry::create( 0.75f, 64, 32 ), material );
  scene->add( mesh );

  renderer.setClearColor( Color(0x050505), 0 );

  /////////////////////////////////////////////////////////////////////////

  window.animate( [&]( float dt ) -> bool {

    time += dt;
    material->uniforms[ "time" ].value = time;

    mesh->rotation().x += 0.1f * dt;
    mesh->rotation().y += 0.5f * dt;

    renderer.render( *scene, *camera );

    return true;

  } );

}
コード例 #7
0
MStatus RadiosityRenderer::doIt(const MArgList &args)
{
	this->args = args;
	windowWidth = 640;
	windowHeight = 480;
	
	SDL_Window *window = SDL_CreateWindow( "Radiosity Renderer Viewport", 0, 0, 640, 480,
										   SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE );
	
	SDL_GLContext glcontext = SDL_GL_CreateContext(window);
	
		
	glClearColor(0,0,0,1);
	glClear(GL_COLOR_BUFFER_BIT);
	
	M3dView curView = M3dView::active3dView();
	MDagPath camDagPath;
	curView.getCamera( camDagPath );
	
	IterateThroughDag();
	//Pass DAG to renderer, let renderer render scene...
	
	SDL_GL_MakeCurrent(window, glcontext);
	GLRenderer renderer = GLRenderer(640,480);
	renderer.RenderToScreen();
	
	SDL_GL_SwapWindow(window);
	
	//Write pixels to render window...
	
	prepareRenderView();
	SDL_GL_MakeCurrent(window, glcontext);
	renderBufferToRenderView();

	sleep(1);
	SDL_GL_DeleteContext(glcontext);
	SDL_DestroyWindow(window);
	SDL_Quit();
	
	return MS::kSuccess;
}
コード例 #8
0
void	GL_InitScene()
{
	Cvar_Register(&gfx_doubleSided);
	Cvar_Register(&gfx_separate_specular_color);
	Cvar_Register(&gfx_ambient_and_diffuse);
	Cvar_Register(&gfx_render);
	Cvar_Register(&gfx_maxlightsperpass);
	Cvar_Register(&gfx_multipassLighting);
	Cvar_Register(&gfx_nicerFog);
	Cvar_Register(&gfx_octreeDepth);
	Cvar_Register(&gfx_sortAll);
	Cvar_Register(&gfx_depthNormalPass);
	Cvar_Register(&gfx_debugoctree);
	Cvar_Register(&gfx_useBuckets);
	Cvar_Register(&gfx_niceEffects);
	Cvar_Register(&gfx_debugCamera);
	
	GL_InitTerrain();
	GL_InitModel();
	GL_InitWater();
	GL_InitClouds();
	GL_InitWeather();

	if (gl_ext_texenv_combine.integer)  //we'll be using 2x modulation
	{
		Cvar_Set("vid_overbrightNormalize", "0.5");
	}

	GL_InitShadow();
	GL_InitPostProcessing();
	
	screen_target = new GLRenderTarget();

	glScreen = screen_target;
	
	if(gfx_postProcEnabled.integer)
		zPass = new DepthPass();
	
	glGetIntegerv(GL_MAX_LIGHTS, &glMaxLights);
	
	renderer.reset();
}
コード例 #9
0
ファイル: GLRenderer.cpp プロジェクト: FabrizioPerria/OpenGL
void GLRenderer::drawCallback(void)
{
	GLRenderer* r = GLRenderer::getInstance();
	r->draw();
}
コード例 #10
0
ファイル: BasicDemo.cpp プロジェクト: ioncore/spark-opengles
// Main function
int main(int argc, char *argv[])
{
#if defined(DEBUG) | defined(_DEBUG)
	_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
  return 0;
	// random seed
	randomSeed = static_cast<unsigned int>(time(NULL));
	
	// Sets the update step
	System::setClampStep(true,0.1f);			// clamp the step to 100 ms
	System::useAdaptiveStep(0.001f,0.01f);		// use an adaptive step from 1ms to 10ms (1000fps to 100fps)

	SDL_Event event;

	// inits SDL
	SDL_Init(SDL_INIT_VIDEO);
	//SDL_WM_SetCaption("SPARK Basic Demo",NULL);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);	// double buffering

	// vsync
	//+SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL,0);
	
	//+SDL_SetVideoMode(0,0,32, SDL_OPENGL | SDL_FULLSCREEN);
	SDL_ShowCursor(0);

	//+SDL_Surface screen = *SDL_GetVideoSurface();
  screenWidth = 640;
  screenHeight = 480;
	SDL_Window* window = SDL_CreateWindow("OpenGL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, screenWidth, screenHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN);
  renderFirstFrame();

	// inits openGL

	screenRatio = (float)screenWidth / (float)screenHeight;
	
	glClearColor(0.0f,0.0f,0.0f,1.0f);
	glViewport(0,0,screenWidth,screenHeight);

	// Loads texture font
	FTGLTextureFont font = FTGLTextureFont("res/font.ttf");
	if(font.Error())
		return 1;
	font.FaceSize(24);
	fontPtr = &font;

	// Loads particle texture
	GLuint textureParticle;
	if (!loadTexture(textureParticle,"res/point.bmp",GL_ALPHA,/*GL_CLAMP*/GL_CLAMP_TO_EDGE,false))
		return 1;

	// Inits Particle Engine
	Vector3D gravity(0.0f,-0.8f,0.0f);

	// Renderers
	GLPointRenderer* basicRenderer = GLPointRenderer::create();

	GLRenderer* particleRenderer = NULL;
	// We use pointSprites only if it is available and if the GL extension point parameter is available
	if ((GLPointRenderer::loadGLExtPointSprite())&&(GLPointRenderer::loadGLExtPointParameter()))
	{
		GLPointRenderer* pointRenderer = GLPointRenderer::create();
		pointRenderer->setType(POINT_SPRITE);
		pointRenderer->setTexture(textureParticle);
		pointRenderer->setTextureBlending(GL_MODULATE);
		pointRenderer->enableWorldSize(true);
		GLPointRenderer::setPixelPerUnit(45.0f * PI / 180.f,screenHeight);
		pointRenderer->setSize(0.05f);
		particleRenderer = pointRenderer;
	}
	else // we use quads
	{
		GLQuadRenderer* quadRenderer = GLQuadRenderer::create();
		quadRenderer->setTexturingMode(TEXTURE_2D);
		quadRenderer->setTexture(textureParticle);
		quadRenderer->setTextureBlending(GL_MODULATE);
		quadRenderer->setScale(0.05f,0.05f);
		particleRenderer = quadRenderer;
	}

	particleRenderer->setBlending(BLENDING_ADD);
	particleRenderer->enableRenderingHint(DEPTH_WRITE,false);

	// Model
	Model* particleModel = Model::create(FLAG_RED | FLAG_GREEN | FLAG_BLUE | FLAG_ALPHA);
	particleModel->setParam(PARAM_ALPHA,0.8f); // constant alpha
	particleModel->setLifeTime(8.0f,8.0f);

	// Emitter
	SphericEmitter* particleEmitter = SphericEmitter::create(Vector3D(0.0f,1.0f,0.0f),0.1f * PI,0.1f * PI);
	particleEmitter->setZone(Point::create(Vector3D(0.0f,0.015f,0.0f)));
	particleEmitter->setFlow(250);
	particleEmitter->setForce(1.5f,1.5f);

	// Obstacle
	Plane* groundPlane = Plane::create();
	Obstacle* obstacle = Obstacle::create(groundPlane,INTERSECT_ZONE,0.6f,1.0f);

	// Group
	particleGroup = Group::create(particleModel,2100);
	particleGroup->addEmitter(particleEmitter);
	particleGroup->addModifier(obstacle);
	particleGroup->setRenderer(particleRenderer);
	particleGroup->setGravity(gravity);
	
	particleSystem = System::create();
	particleSystem->addGroup(particleGroup);
	
	bool exit = false;
	bool paused = false;

	// renderValue :
	// 0 : normal
	// 1 : basic render
	// 2 : no render
	unsigned int renderValue = 0;

	float step = 0.0f;

	cout << "\nSPARK FACTORY AFTER INIT :" << endl;
	SPKFactory::getInstance().traceAll();

	SDL_Delay(3000);
	while (SDL_PollEvent(&event)){}
	
	std::deque<unsigned int> frameFPS;
	frameFPS.push_back(SDL_GetTicks());

	while(!exit)
	{
		while (SDL_PollEvent(&event))
		{
			// if esc is pressed, exit
			if ((event.type == SDL_KEYDOWN)&&(event.key.keysym.sym == SDLK_ESCAPE))
				exit = true;

			// if del is pressed, reinit the system
			if ((event.type == SDL_KEYDOWN)&&(event.key.keysym.sym == SDLK_DELETE))
				particleSystem->empty();

			// if F1 is pressed, we display or not the text
			if ((event.type == SDL_KEYDOWN)&&(event.key.keysym.sym == SDLK_F1))
			{
				--drawText;
				if (drawText < 0)
					drawText = 2;
			}

			// if F2 is pressed, we display or not the bounding boxes
			if ((event.type == SDL_KEYDOWN)&&(event.key.keysym.sym == SDLK_F2))
			{
				particleGroup->enableAABBComputing(!particleGroup->isAABBComputingEnabled());

				if (paused)
					particleSystem->computeAABB();
			}

			// if F4 is pressed, the renderers are changed
			if ((event.type == SDL_KEYDOWN)&&(event.key.keysym.sym == SDLK_F4))
			{
				renderValue = (renderValue + 1) % 3;

				switch (renderValue)
				{
				case 0 :
					particleGroup->setRenderer(particleRenderer);
					break;

				case 1 :
					particleGroup->setRenderer(basicRenderer);
					break;

				case 2 :
					particleGroup->setRenderer(NULL);
					break;
				}
			}

			// if pause is pressed, the system is paused
			if ((event.type == SDL_KEYDOWN)&&(event.key.keysym.sym == SDLK_PAUSE))
				paused = !paused;

			// Moves the camera with the mouse
			if (event.type == SDL_MOUSEMOTION)
			{
				angleY += event.motion.xrel * 0.05f;
				angleX += event.motion.yrel * 0.05f;
				angleX = min(179.0f,max(1.0f,angleX)); // we cannot look under the ground
			}

			// Zoom in and out
			if (event.type == SDL_MOUSEBUTTONDOWN)
			{
				//if (event.button.button == SDL_BUTTON_WHEELDOWN)
				//	camPosZ = min(10.0f,camPosZ + 0.5f);
				//if (event.button.button == SDL_BUTTON_WHEELUP)
				//	camPosZ = max(0.5f,camPosZ - 0.5f);
			}
		}

		if (!paused)
		{
			// Changes the color of the model over time
			step += deltaTime * 0.0005f;
			particleModel->setParam(PARAM_RED,0.6f + 0.4f * sin(step));
			particleModel->setParam(PARAM_GREEN,0.6f + 0.4f * sin(step + PI * 2.0f / 3.0f));
			particleModel->setParam(PARAM_BLUE,0.6f + 0.4f * sin(step + PI * 4.0f / 3.0f));

			// Updates particle system
			particleSystem->update(deltaTime * 0.001f);	// 1 defined as a second
		}

		// Renders scene
		render();

		// Computes delta time
		int time = SDL_GetTicks();
		deltaTime = time - frameFPS.back();

		frameFPS.push_back(time);

		while((frameFPS.back() - frameFPS.front() > 1000)&&(frameFPS.size() > 2))
			frameFPS.pop_front();

		// Updates info strings
		strNbParticles = STR_NB_PARTICLES + int2Str(particleSystem->getNbParticles());
		int fps = static_cast<int>(((frameFPS.size() - 1) * 1000.0f) / (frameFPS.back() - frameFPS.front()));
		if (drawText == 2)
			strFps = STR_FPS + int2Str(fps);	
		else
			strFps = int2Str(fps);
	}

	cout << "\nSPARK FACTORY BEFORE DESTRUCTION :" << endl;
	SPKFactory::getInstance().traceAll();
	SPKFactory::getInstance().destroyAll();
	cout << "\nSPARK FACTORY AFTER DESTRUCTION :" << endl;
	SPKFactory::getInstance().traceAll();
	SPKFactory::destroyInstance();
	SDL_Quit();

	cout << endl;
	system("pause"); // Waits for the user to close the console

	return 0;
}
コード例 #11
0
void	GL_RenderScene(camera_t *camera, vec3_t userpos, unsigned int sceneRenderFlags)
{
	if (!world.cl_loaded || !gfx_render.integer)
	{
		//GL_2dMode();
		return;
	}
	
	static float lasttime=0;
	camera_t sunCam;
	Pass basePass;
	worldLight_t rimLight;
	float lerp;
	float ambBoost = (vid_realbright.integer && gfx_GLSLQuality.integer<=1) ? vid_realbrightMult.value : 1.0f;
	
	basePass.setViewer(camera);
	scene_cam = camera;
	
	sunLight.origin[0] = -wr_sun_x.value;
	sunLight.origin[1] = -wr_sun_y.value;
	sunLight.origin[2] = -wr_sun_z.value;
	
	memset(&rimLight, 0, sizeof(worldLight_t));
	
	M_MultVec3(sunLight.origin, -1, rimLight.origin);
	rimLight.type = LIGHT_DIRECTIONAL;
	
	//// SHADOW MAP RENDER ////
	//shadow pass, render to texture
	if(gfx_shadow.integer && gfx_shadowQuality.integer >= 1 && gfx_GLSLQuality.integer>1)
	{
		vec3_t wmin, wmax, sunLook;

		
			
			World_GetBounds(wmin, wmax);
			//SET_VEC3(sunLook, (wmax[0]-wmin[0])*.5f, (wmax[1]-wmin[1])*.5f, 0 * .5f);
			M_MultVec3(camera->viewaxis[AXIS_FORWARD], camera->farclip*0.05, sunLook);
			M_AddVec2(sunLook, camera->origin, sunLook);
			
			Cam_DefaultCamera(&sunCam, gfx_shadowSize.integer, gfx_shadowSize.integer, 2, 8192);
		if(wr_sun_z.value < 0) {
			SET_VEC3(sunCam.origin, -wr_sun_x.value, -wr_sun_y.value, -wr_sun_z.value);
		} else {
			SET_VEC3(sunCam.origin, wr_sun_x.value, wr_sun_y.value, wr_sun_z.value);
		}
			M_Normalize(sunCam.origin);
			M_MultVec3(sunCam.origin, wmax[0], sunCam.origin);
			sunCam.origin[0]+=sunLook[0];
			sunCam.origin[1]+=sunLook[1];
			M_SubVec3(sunLook, sunCam.origin, sunCam.viewaxis[AXIS_FORWARD]);
		
			M_GetAxisFromForwardVec(sunCam.viewaxis[AXIS_FORWARD], sunCam.viewaxis);
			sunCam.fovy = 50;
			sunCam.time = camera->time;
			sunCam.fog_far=100000;
			sunCam.fog_near=99999;
			sunCam.flags |= CAM_NO_SKY;
			
			//CSM setup
			if(gfx_shadowQuality.integer >= 2) {
				shadowSplit=0;
				for(int i=0;i<gfx_shadowQuality.integer;i++) {
					cascadedPass[i].setViewer(&sunCam);
					renderer.addPass(&cascadedPass[i]);
				}
			} else {
				shadowPass.setViewer(&sunCam);
				renderer.addPass(&shadowPass);
			}
		
		
	} else if( gfx_GLSLQuality.integer > 1 ) {
		renderer.addPass(&shadowPass);
	}
	
	if(gfx_postProcEnabled.integer && gfx_GLSLQuality.integer>1 && (gfx_depthNormalPass.integer || gfx_postSSAO.integer)) {
		zPass->setViewer(camera);
		renderer.addPass(zPass);
	}
	
	basePass.setDepthFunc(GL_LEQUAL);
	basePass.setDepthMask(true);
	basePass.clearDepth(true);
	
	if(gfx_GLSLQuality.integer>1 && gfx_postProcessing.integer)
		basePass.setTarget(screenPostTarget);
	else
		basePass.setTarget(glScreen);
	
	renderer.addPass(&basePass);
	
	//// BUILD RENDER LIST ////
	
	// sun/moon
	
	if(wr_sun_z.value < 0) {
		lerp = CLAMP(fabs(-1 - cos(wr_sun_phi.value)), 0, 1);
		
		//Console_Printf("phi %f lerp %f\n", wr_sun_phi.value, lerp);
		
		//setup sun light color and ambient
		sunLight.ambient[0] = obj_ambient_r.value*ambBoost;
		sunLight.ambient[1] = obj_ambient_g.value*ambBoost;
		sunLight.ambient[2] = obj_ambient_b.value*ambBoost;
		sunLight.color[0] = obj_light0_r.value*.9;
		sunLight.color[1] = obj_light0_g.value*.9;
		sunLight.color[2] = obj_light0_b.value*.98;
		
		rimLight.ambient[0] = 0;
		rimLight.ambient[1] = 0;
		rimLight.ambient[2] = 0;
		rimLight.color[0] = lerp*obj_light1_r.value*.9;
		rimLight.color[1] = lerp*obj_light1_g.value*.9;
		rimLight.color[2] = lerp*obj_light1_b.value*.98;
	} else {
		if(wr_sun_phi.value < 5.23f && wr_sun_phi.value > 1.0472f)
			lerp = CLAMP(fabs(1-cos(3*(M_PI-wr_sun_phi.value))), 0, 1);
		else
			lerp = 0;
		
		//Console_Printf("phi %f lerp %f cos %f\n", wr_sun_phi.value, lerp, cos(3*(M_PI-wr_sun_phi.value)));
		
		//the lights need to flip
		M_MultVec3(sunLight.origin, -1, sunLight.origin);
		M_MultVec3(rimLight.origin, -1, rimLight.origin);
		
		//setup moon light color and ambient
		sunLight.ambient[0] = obj_ambient_r.value*ambBoost;
		sunLight.ambient[1] = obj_ambient_g.value*ambBoost;
		sunLight.ambient[2] = obj_ambient_b.value*ambBoost;
		sunLight.color[0] = obj_light1_r.value*.9;
		sunLight.color[1] = obj_light1_g.value*.9;
		sunLight.color[2] = obj_light1_b.value*.98;
		
		rimLight.ambient[0] = 0;
		rimLight.ambient[1] = 0;
		rimLight.ambient[2] = 0;
		rimLight.color[0] = lerp*obj_light0_r.value*.9;
		rimLight.color[1] = lerp*obj_light0_g.value*.9;
		rimLight.color[2] = lerp*obj_light0_b.value*.98;
	}
	
	renderer.addLight(&sunLight, NULL, 0);
	renderer.addLight(&rimLight, NULL, 0);
	
	// The deal here is rather than changing the code in scene.cpp to support the
	// new renderer, we just "import" all the scene data
	
	//// SCENE DATA ////
	
	lightCount = 0;
	//objects
	scenelist_t *list;
	for (list = scenelist; list; list = list->next)
	{
		//if(list->cull)
		//	continue;
		
		switch (list->obj.objtype)
		{
			case OBJTYPE_MODEL:
				GL_AddModelToLists(&list->obj);
				break;
			case OBJTYPE_LIGHT:
				GL_AddLight(0, &list->obj);
				break;
			default:
				break;
		}
	}
	
	//polys
	scenefacelist_t *flist;
	for (flist = scenefacelist; flist; flist = flist->next)
	{
		renderer.addPoly(flist, NULL, flist->shader);
	}
	
	//decals
	for (flist = scenefacelist_decals; flist; flist = flist->next)
	{
		renderer.addPoly(flist,  NULL, flist->shader);
	}
	
	//lights
	scenelightlist_t *llist;
	for (llist = scenelightlist; llist; llist = llist->next)
	{
		worldLight_t *l = &worldlights[lightCount++];
		M_CopyVec3(llist->light.color, l->color);
		M_CopyVec3(llist->light.pos, l->origin);
		renderer.addLight(l, NULL, 0);
	}
	
	//// END SCENE DATA ////
	
	//// ENVIRO ////
	
	if(!(camera->flags & CAM_NO_WORLD)) {
		
		//terrain
		if (!(scene_cam->flags & CAM_NO_TERRAIN))
			renderer.addCustomListItem(&terrainItem, false);
		
		//sprites
		for (std::list<scenelist_t*>::iterator itr = spritelist.begin(); itr != spritelist.end(); itr++)
		{
			scenelist_t *sprite = *itr;
			renderer.addSprite(sprite, &sprite->obj, sprite->obj.shader);
		}
		
		//clouds (at the back)
		if(gfx_sky.integer) {
			renderer.addCustomListItem(&cloudsItem, false);
		}
	
		if(gfx_water.integer) {
			waterItem.set(NULL,NULL,0);
			renderer.addCustomListItem(&waterItem, false);
		}
		
		//sky
		if (gfx_sky.integer) {
			if(Cvar_GetInteger("tl_suntod") <= 1440) 
				sky.setTimeofDay(Cvar_GetValue("tl_suntod")/1440.0f);
			else
				sky.setTimeofDay((Cvar_GetValue("tod_sunminute"))/1440.0f);
			
			//renderer.addListItem(&clouds, false);
			renderer.addCustomListItem(&sky, false);
		}
		
		//// FX LAYER ////
		
		//polys
		for (flist = scenefxfacelist; flist; flist = flist->next)
		{
			renderer.addPolyFX(flist, NULL, flist->shader);
		}
		
		//decals
		for (flist = scenefxfacelist_decals; flist; flist = flist->next)
		{
			renderer.addPolyFX(flist,  NULL, flist->shader);
		}
		
		//sprites
		for (std::list<scenelist_t*>::iterator itr = spritefxlist.begin(); itr != spritefxlist.end(); itr++)
		{
			scenelist_t *sprite = *itr;
			renderer.addSpriteFX(sprite, &sprite->obj, sprite->obj.shader);
		}
	}
	
	//// RENDER ////
	
	renderer.render(camera->time-lasttime);
	
	lasttime = camera->time;
}
コード例 #12
0
void	GL_ClearStaticScene()
{
	renderer.clearStatics();
}
コード例 #13
0
ファイル: particles_sprites.cpp プロジェクト: ronj/invent
void particles_sprites( GLWindow& window, GLRenderer& renderer ) {

  auto camera = PerspectiveCamera::create(
    75, ( float )renderer.width() / renderer.height(), 1.f, 2000
  );
  camera->position().z = 1000;

  auto scene = Scene::create();
  scene->fog = FogExp2::create( 0x000000, .0008f );

  auto geometry = Geometry::create();

  auto sprite1 = ImageUtils::loadTexture( threeDataPath("textures/sprites/snowflake1.png") );
  auto sprite2 = ImageUtils::loadTexture( threeDataPath("textures/sprites/snowflake2.png") );
  auto sprite3 = ImageUtils::loadTexture( threeDataPath("textures/sprites/snowflake3.png") );
  auto sprite4 = ImageUtils::loadTexture( threeDataPath("textures/sprites/snowflake4.png") );
  auto sprite5 = ImageUtils::loadTexture( threeDataPath("textures/sprites/snowflake5.png") );

  const auto particleCount = 10000;
  geometry->vertices.reserve( particleCount );

  std::generate_n( std::back_inserter( geometry->vertices ),
                   particleCount,
                   [] { return Vector3( Math::random(-1000.f, 1000.f),
                                        Math::random(-1000.f, 1000.f),
                                        Math::random(-1000.f, 1000.f) ); } );

  std::vector<Material::Ptr> materials;
  auto addParticleSystem = [&]( const Vector3& color, const Texture::Ptr& sprite, float size ) {

    auto material = ParticleSystemMaterial::create(
      Material::Parameters().add( "size", size )
                            .add( "map", sprite )
                            .add( "blending", THREE::AdditiveBlending )
                            .add( "depthTest", false )
                            .add( "transparent", true )
    );

    materials.push_back( material );
    material->color.setHSL( color[0], color[1], color[2] );

    auto particles = ParticleSystem::create( geometry, material );

    particles->rotation() = Euler( Math::random() * 6,
                                   Math::random() * 6,
                                   Math::random() * 6 );

    scene->add( particles );
  };

  typedef std::tuple<Vector3, Texture::Ptr, float> ColorSpriteSize;
  std::array<ColorSpriteSize, 5> params = {
    ColorSpriteSize( Vector3(  1.f, 0.2f,  0.5f), sprite2, 20.f ),
    ColorSpriteSize( Vector3(0.95f, 0.1f,  0.5f), sprite3, 13.f ),
    ColorSpriteSize( Vector3(0.90f, 0.05f, 0.5f), sprite1, 10.f ),
    ColorSpriteSize( Vector3(0.85f, 0.f,   0.5f), sprite5, 8.f ),
    ColorSpriteSize( Vector3(0.80f, 0.f,   0.5f), sprite4, 5.f )
  };
  for ( const auto& param : params ) {
    addParticleSystem( std::get<0>(param), std::get<1>(param), std::get<2>(param) );
  }

  /////////////////////////////////////////////////////////////////////////

  auto mouseX = 0.f, mouseY = 0.f;
  window.addEventListener( SDL_MOUSEMOTION, [&]( const SDL_Event& event ) {
    mouseX = 2.f * ( ( float )event.motion.x / renderer.width()  - 0.5f );
    mouseY = 2.f * ( ( float )event.motion.y / renderer.height() - 0.5f );
  } );

  window.addEventListener( SDL_WINDOWEVENT, [&]( const SDL_Event& event ) {
    if (event.window.event != SDL_WINDOWEVENT_RESIZED) return;
    camera->aspect = ( float )event.window.data1 / event.window.data2;
    camera->updateProjectionMatrix();
    renderer.setSize( event.window.data1, event.window.data2 );
  } );

  /////////////////////////////////////////////////////////////////////////

  auto time = 0.f;

  window.animate( [&]( float dt ) -> bool {

    time += dt * .05f;

    camera->position().x += ( -1000.f * mouseX - camera->position().x ) * 3 * dt;
    camera->position().y += (  1000.f * mouseY - camera->position().y ) * 3 * dt;
    camera->lookAt( scene->position() );

    for ( size_t i = 0; i < scene->children.size(); ++i ) {
      auto& object = *scene->children[ i ];
      if ( object.type() == THREE::ParticleSystem ) {
        object.rotation().y = time * ( i < 4 ? i + 1 : - ( (int)i + 1 ) );
      }
    }

    for ( size_t i = 0; i < materials.size(); ++i ) {
      auto& color = std::get<0>(params[ i ]);
      const auto h = Math::fmod( 360.f * ( color[0] + time ), 360.f ) / 360.f;
      materials[ i ]->color.setHSL( h, color[ 1 ], color[ 2 ] );
    }

    renderer.render( *scene, *camera );

    return true;

  } );

}
コード例 #14
0
void	GL_AddSprite(residx_t shader, scenelist_t *sp, sceneobj_t *obj, bool bStatic)
{
	renderer.addSprite(sp, obj, shader, bStatic);
}
コード例 #15
0
ファイル: geometries.cpp プロジェクト: ronj/invent
void geometries( GLWindow& window, GLRenderer& renderer ) {

    auto camera = PerspectiveCamera::create(
                      45, ( float )renderer.width() / renderer.height(), 10, 20000
                  );
    camera->position().y = 700;

    auto scene = Scene::create();

    scene->add( AmbientLight::create( 0x404040 ) );

    auto light = DirectionalLight::create( 0xffffff );
    light->position().set( 0, 1, 0 );
    scene->add( light );

    auto map = ImageUtils::loadTexture( threeDataPath( "textures/UV_Grid_Sm.jpg" ) );
    map->wrapS = map->wrapT = THREE::RepeatWrapping;
    map->anisotropy = 16;

    auto material = MeshLambertMaterial::create(
                        Material::Parameters()
                        .add( "ambient", Color( 0xbbbbbb ) )
                        .add( "map", map )
                        .add( "side", THREE::DoubleSide )
                    );

    //

    auto sphere = Mesh::create( SphereGeometry::create( 75, 20, 10 ), material );
    sphere->position().set( -400, 0, 200 );
    scene->add( sphere );

    auto ico = Mesh::create( IcosahedronGeometry::create( 75, 1 ), material );
    ico->position().set( -200, 0, 200 );
    scene->add( ico );

    auto octa = Mesh::create( OctahedronGeometry::create( 75, 2 ), material );
    octa->position().set( 0, 0, 200 );
    scene->add( octa );

    auto tetra = Mesh::create( TetrahedronGeometry::create( 75, 0 ), material );
    tetra->position().set( 200, 0, 200 );
    scene->add( tetra );

    //

    auto plane = Mesh::create( PlaneGeometry::create( 100, 100, 4, 4 ), material );
    plane->position().set( -400, 0, 0 );
    scene->add( plane );

    auto cube = Mesh::create( BoxGeometry::create( 100, 100, 100, 4, 4, 4 ), material );
    cube->position().set( -200, 0, 0 );
    scene->add( cube );

    auto circle = Mesh::create( CircleGeometry::create( 50, 20, 0, Math::PI() * 2 ), material );
    circle->position().set( 0, 0, 0 );
    scene->add( circle );

    auto ring = Mesh::create( RingGeometry::create( 10, 50, 20, 5, 0, Math::PI() * 2 ), material );
    ring->position().set( 200, 0, 0 );
    scene->add( ring );

    auto cylinder = Mesh::create( CylinderGeometry::create( 25, 75, 100, 40, 5 ), material );
    cylinder->position().set( 400, 0, 0 );
    scene->add( cylinder );

    //

    std::vector<Vector3> points;
    for ( auto i = 0; i < 50; i ++ ) {

        points.push_back( Vector3( Math::sin( (float)i * 0.2 ) * Math::sin( (float)i * 0.1 ) * 15 + 50, 0, ( (float)i - 5 ) * 2 ) );

    }

    auto lathe = Mesh::create( LatheGeometry::create( points, 20 ), material );
    lathe->position().set( -400, 0, -200 );
    scene->add( lathe );

    auto torus = Mesh::create( TorusGeometry::create( 50, 20, 20, 20 ), material );
    torus->position().set( -200, 0, -200 );
    scene->add( torus );

    auto torusKnot = Mesh::create( TorusKnotGeometry::create( 50, 10, 50, 20 ), material );
    torusKnot->position().set( 0, 0, -200 );
    scene->add( torusKnot );

    auto axis = AxisHelper::create( 50 );
    axis->position().set( 200, 0, -200 );
    scene->add( axis );

    auto arrow = ArrowHelper::create( Vector3( 0, 1, 0 ), Vector3( 0, 0, 0 ) );
    arrow->setLength(50);
    arrow->position().set( 400, 0, -200 );
    scene->add( arrow );

    /////////////////////////////////////////////////////////////////////////

    window.addEventListener( SDL_WINDOWEVENT, [&]( const SDL_Event& event ) {
        if (event.window.event != SDL_WINDOWEVENT_RESIZED) return;
        camera->aspect = ( float )event.window.data1 / event.window.data2;
        camera->updateProjectionMatrix();
        renderer.setSize( event.window.data1, event.window.data2 );
    } );

    /////////////////////////////////////////////////////////////////////////

    auto time = 0.f;
    int benchmarkFrames = 100000;

    window.animate( [&]( float dt ) -> bool {

        time += dt;

        camera->position().x = Math::cos( time * 0.2 ) * 800;
        camera->position().z = Math::sin( time * 0.2 ) * 800;
        camera->lookAt( scene->position() );

        for ( size_t i = 0; i < scene->children.size(); i ++ ) {

            auto& object = scene->children[ i ];

            object->rotation().x = time * 1;
            object->rotation().y = time * 0.25;

        }

        renderer.render( *scene, *camera );

        return --benchmarkFrames > 0;

    } );

}
コード例 #16
0
void	GL_AddMesh(residx_t shader, mesh_t *mesh, sceneobj_t *obj, int meshNum, bool bStatic)
{
	renderer.addMesh(mesh, obj, shader, meshNum, bStatic);
}
コード例 #17
0
ファイル: trails.cpp プロジェクト: ronj/invent
void trails( GLWindow& window, GLRenderer& renderer ) {

  renderer.sortObjects = false;
  renderer.autoClearColor = false;

  // Camera
  auto camera = PerspectiveCamera::create(
    60,
    (float)renderer.width() / renderer.height(),
    1, 10000
  );
  camera->position().set( 100000, 0, 3200 );

  // Scene
  auto scene = Scene::create();

  // Geometries
  std::array<Color, 4> colors = { Color(0x000000), Color(0xff0080), Color(0x8000ff), Color(0xffffff) };
  auto geometry = Geometry::create();

  for ( int i = 0; i < 2000; i ++ ) {
    Vertex vertex;
    vertex.x = Math::random(-2000.f, 2000.f);
    vertex.y = Math::random(-2000.f, 2000.f);
    vertex.z = Math::random(-2000.f, 2000.f);
    geometry->vertices.push_back( vertex );
    geometry->colors.push_back( colors[ (int)Math::floor( Math::random() * colors.size() ) ] );
  }

  // Materials
  auto material = ParticleSystemMaterial::create(
    Material::Parameters().add("color", Color(0xcccccc))
                          .add("size", 1.0f)
                          .add("vertexColors", THREE::VertexColors)
                          .add("depthTest", false)
                          .add("opacity", 0.5f)
                          .add("sizeAttenuation", false)
  );

  auto mesh = ParticleSystem::create( geometry, material );
  scene->add( mesh );

  auto mouseX = 0.f, mouseY = 0.f;
  window.addEventListener(SDL_MOUSEMOTION, [&]( const SDL_Event& event ) {
    mouseX = 2.f * ((float)event.motion.x / renderer.width()  - 0.5f);
    mouseY = 2.f * ((float)event.motion.y / renderer.height() - 0.5f);
  });

  // Rendering
  window.animate ( [&]( float dt ) -> bool {

    camera->position().x += ( 1000.f * mouseX - camera->position().x ) * 5 * dt;
    camera->position().y += ( 1000.f * mouseY - camera->position().y ) * 5 * dt;
    camera->lookAt( scene->position() );

    renderer.render( *scene, *camera );

    return true;

  } );

}
コード例 #18
0
ファイル: main.cpp プロジェクト: sirikata/prox
int main(int argc, char** argv) {
    using namespace Prox::Simulation;

    std::string SEED_ARG("--seed=");
    std::string DISPLAY_ARG("--display=");
    // Simulation params
    std::string DURATION_ARG("--duration=");
    std::string ITERATIONS_ARG("--iterations=");
    std::string REALTIME_ARG("--realtime=");
    std::string TIMESTEP_ARG("--timestep="); // in milliseconds
    // Object params
    std::string NOBJECTS_ARG("--nobjects=");
    std::string STATIC_OBJECTS_ARG("--static-objects=");
    std::string MOVING_FRAC_ARG("--moving-frac=");
    std::string CSV_ARG("--csv=");
    std::string CSV_MOTION_ARG("--csvmotion=");
    // Handler params
    std::string HANDLER_ARG("--handler=");
    std::string BRANCH_ARG("--branch=");
    // Querier params
    std::string NQUERIES_ARG("--nqueries=");
    std::string STATIC_QUERIES_ARG("--static-queries=");

    unsigned int seed = 0;
    bool display = false;

    int duration = 0; // seconds
    int iterations = 0; // iterations before termination
    bool realtime = true; // realtime or simulated time steps
    int timestep = 50;

    int nobjects = 10000;
    float moving_frac = 1.0f;
    std::string csvfile = "";
    std::string csvmotionfile = "";

    std::string handler_type = "rtree";
    int branching = 16;

    int nqueries = 50;
    bool static_queries = false;

    for(int argi = 0; argi < argc; argi++) {
        std::string arg(argv[argi]);
        if (arg.find(SEED_ARG) != std::string::npos) {
            std::string seed_arg = arg.substr(SEED_ARG.size());
            seed = boost::lexical_cast<int>(seed_arg);
        }
        else if (arg.find(DISPLAY_ARG) != std::string::npos) {
            std::string display_arg = arg.substr(DISPLAY_ARG.size());
            display = convert_bool(display_arg);
        }

        else if (arg.find(DURATION_ARG) != std::string::npos) {
            std::string duration_arg = arg.substr(DURATION_ARG.size());
            duration = boost::lexical_cast<int>(duration_arg);
        }
        else if (arg.find(ITERATIONS_ARG) != std::string::npos) {
            std::string iterations_arg = arg.substr(ITERATIONS_ARG.size());
            iterations = boost::lexical_cast<int>(iterations_arg);
        }
        else if (arg.find(REALTIME_ARG) != std::string::npos) {
            std::string realtime_arg = arg.substr(REALTIME_ARG.size());
            realtime = convert_bool(realtime_arg);
        }
        else if (arg.find(TIMESTEP_ARG) != std::string::npos) {
            std::string timestep_arg = arg.substr(TIMESTEP_ARG.size());
            timestep = boost::lexical_cast<int>(timestep_arg);
        }

        else if (arg.find(NOBJECTS_ARG) != std::string::npos) {
            std::string nobjects_arg = arg.substr(NOBJECTS_ARG.size());
            nobjects = boost::lexical_cast<int>(nobjects_arg);
        }
        else if (arg.find(STATIC_OBJECTS_ARG) != std::string::npos) {
            std::string static_arg = arg.substr(STATIC_OBJECTS_ARG.size());
            bool static_objects = convert_bool(static_arg);
            if (static_objects) moving_frac = 0.0f;
        }
        else if (arg.find(MOVING_FRAC_ARG) != std::string::npos) {
            std::string moving_arg = arg.substr(MOVING_FRAC_ARG.size());
            moving_frac = boost::lexical_cast<float>(moving_arg);
        }
        else if (arg.find(CSV_ARG) != std::string::npos) {
            csvfile = arg.substr(CSV_ARG.size());
        }
        else if (arg.find(SEED_ARG) != std::string::npos) {
            std::string seed_arg = arg.substr(SEED_ARG.size());
            seed = boost::lexical_cast<int>(seed_arg);
        }

        else if (arg.find(HANDLER_ARG) != std::string::npos) {
            handler_type = arg.substr(HANDLER_ARG.size());
        }
        else if (arg.find(BRANCH_ARG) != std::string::npos) {
            std::string branch_arg = arg.substr(BRANCH_ARG.size());
            branching = boost::lexical_cast<int>(branch_arg);
        }

        else if (arg.find(NQUERIES_ARG) != std::string::npos) {
            std::string nqueries_arg = arg.substr(NQUERIES_ARG.size());
            nqueries = boost::lexical_cast<int>(nqueries_arg);
        }
        else if (arg.find(STATIC_QUERIES_ARG) != std::string::npos) {
            std::string static_arg = arg.substr(STATIC_QUERIES_ARG.size());
            static_queries = convert_bool(static_arg);
        }

    }

    srand(seed);

#ifndef LIBPROX_RTREE_DATA
# error "You must define LIBPROX_RTREE_DATA to either LIBPROX_RTREE_DATA_BOUNDS or LIBPROX_RTREE_DATA_MAXSIZE"
#endif
#if LIBPROX_RTREE_DATA == LIBPROX_RTREE_DATA_BOUNDS
    typedef Prox::BoundingSphereData<Prox::DefaultSimulationTraits> NodeData;
#elif LIBPROX_RTREE_DATA == LIBPROX_RTREE_DATA_MAXSIZE
    typedef Prox::MaxSphereData<Prox::DefaultSimulationTraits> NodeData;
#elif LIBPROX_RTREE_DATA == LIBPROX_RTREE_DATA_SIMILARMAXSIZE
    typedef Prox::SimilarMaxSphereData<Prox::DefaultSimulationTraits> NodeData;
#else
# error "Invalid setting for LIBPROX_RTREE_DATA"
#endif

    ManualQueryHandler* handler = NULL;
    if (handler_type == "rtree") {
        handler = new Prox::RTreeManualQueryHandler<Prox::DefaultSimulationTraits, NodeData>(branching);
    }

    Simulator* simulator = new Simulator(handler, duration, Duration::milliseconds((unsigned int)timestep), iterations, realtime);
    GLRenderer* renderer = new GLRenderer(simulator, handler, display);

    BoundingBox3 random_region( Vector3(-100.f, -100.f, -100.f), Vector3(100.f, 100.f, 100.f) );

    int nobjects_moving = nobjects * moving_frac;
    int nobjects_static = nobjects - nobjects_moving;

    // There are various combinations of sources of objects we might need to get
    // to the target number with the right mix. When we need random objects and
    // we've loaded some from another source, we need to make sure we get the
    // region to generate them over correct.

    bool got_static = false;
    bool got_moving = false;

    // First, get objects from csv files.
    if (!csvfile.empty()) {
        simulator->createStaticCSVObjects(csvfile, nobjects_static);
        got_static = true;
    }
    // note: this should be second so that
    if (!csvmotionfile.empty()) {
        assert(!csvfile.empty()); // FIXME we'd like to support this, need to
                                  // figure out bounding box issues for
                                  // generating starting positions
        simulator->createMotionCSVObjects(csvmotionfile, nobjects_moving);
        got_moving = true;
    }

    // Next, take care of leftovers with random objects. Note that we use the
    // existing bounds if some other objects were already loaded.
    if (!got_static && !got_moving)
        simulator->createRandomObjects(random_region, nobjects, moving_frac);
    else if (!got_static && got_moving)
        simulator->createRandomObjects(simulator->region(), nobjects_static, 0.0);
    else if (got_static && !got_moving)
        simulator->createRandomObjects(simulator->region(), nobjects_moving, 1.0);
    // else we don't need any random objects

    // Sometimes we're not perfect, but let's aim for 99% of the target objects.
    assert(simulator->allObjectsSize() >= .99f * nobjects);

    simulator->initialize(/*churn_rate*/0);

    if (!csvmotionfile.empty() && !static_queries)
        simulator->createCSVQueries(nqueries, csvmotionfile);
    else
        simulator->createRandomQueries(nqueries, static_queries);

    simulator->run();

    renderer->run();
    simulator->shutdown();

    delete renderer;
    delete simulator;


    return 0;
}
コード例 #19
0
void shader( GLWindow& window, GLRenderer& renderer ) {

 auto camera = PerspectiveCamera::create(
    60, ( float )renderer.width() / renderer.height(), 1, 10000
  );
  camera->position().z = 300;

  auto scene = Scene::create();
  auto texture = ImageUtils::loadTexture( threeDataPath( "textures/sprites/spark1.png" ) );

  Uniforms uniforms;
  uniforms[ "color" ]      = Uniform( THREE::c, Color( 0xffffff ) );
  uniforms[ "texture" ]    = Uniform( THREE::t, texture.get() );

  Attributes attributes;
  attributes[ "size" ]        = Attribute( THREE::f );
  attributes[ "customColor" ] = Attribute( THREE::c );

  auto shaderMaterial = ShaderMaterial::create(
    vertexShader,
    fragmentShader,
    uniforms,
    attributes,
    Material::Parameters().add( "blending", THREE::AdditiveBlending )
                          .add( "depthTest", false )
                          .add( "transparent", true )
  );

  // Geometries
  const auto radius = 200.f;
  const auto pointCount = 100000;

  auto geometry = Geometry::create();

  auto& vertices = geometry->vertices;
  vertices.reserve( pointCount );

  std::generate_n(
    std::back_inserter(vertices),
    pointCount,
    [=]() -> Vector3 {
      return Vector3( Math::random(-1.f, 1.f),
                      Math::random(-1.f, 1.f),
                      Math::random(-1.f, 1.f) ).multiplyScalar( radius );
    }
  );

  auto sphere = ParticleSystem::create( geometry, shaderMaterial );
  sphere->geometry->dynamic = true;
  sphere->sortParticles = false;

  std::vector<float> values_size( pointCount );
  std::vector<Color> values_color( pointCount );

  for ( int v = 0; v < pointCount; v++ ) {

    values_size[ v ] = 10;
    values_color[ v ].set( 0xffaa00 );

    if ( vertices[ v ].x < 0 )
      values_color[ v ].setHSL( 0.5f + 0.1f * ( (float)v / pointCount ), 0.7f, 0.5f );
    else
      values_color[ v ].setHSL( 0.0f + 0.1f * ( (float)v / pointCount), 0.9f, 0.5f );

  }

  auto& size  = shaderMaterial->attributes[ "size" ];
  auto& color = shaderMaterial->attributes[ "customColor" ];

  size.value  = values_size;
  color.value = values_color;

  scene->add( sphere );

  /////////////////////////////////////////////////////////////////////////

  window.addEventListener( SDL_WINDOWEVENT, [&]( const SDL_Event& event ) {
    if (event.window.event != SDL_WINDOWEVENT_RESIZED) return;
    camera->aspect = ( float )event.window.data1 / event.window.data2;
    camera->updateProjectionMatrix();
    renderer.setSize( event.window.data1, event.window.data2 );
  } );

  /////////////////////////////////////////////////////////////////////////

  auto time = 0.f;

  window.animate( [&]( float dt ) -> bool {

    time += dt;
    sphere->rotation().z = time * 0.03f;

    auto& sizes = size.value.cast<std::vector<float>>();
    for( size_t i = 0; i < sizes.size(); i++ ) {
      sizes[ i ] = 10.f + 9.f * Math::sin( 0.1f * i + time * 3.f );
    }
    size.needsUpdate = true;

    renderer.render( *scene, *camera );

    return true;

  } );

}
コード例 #20
0
ファイル: particles_billboards.cpp プロジェクト: ronj/invent
void particles_billboards( GLWindow& window, GLRenderer& renderer ) {

  auto camera = PerspectiveCamera::create(
    55, ( float )renderer.width() / renderer.height(), 2.f, 2000
  );
  camera->position().z = 1000;

  auto scene = Scene::create();
  scene->fog = FogExp2::create( 0x000000, .001f );

  auto geometry = Geometry::create();

  const auto particleCount = 10000;
  geometry->vertices.reserve( particleCount );

  std::generate_n( std::back_inserter( geometry->vertices ),
                   particleCount,
                   [] { return Vector3( Math::random(-1000.f, 1000.f),
                                        Math::random(-1000.f, 1000.f),
                                        Math::random(-1000.f, 1000.f) ); } );

  auto sprite = ImageUtils::loadTexture(
    threeDataPath("textures/sprites/disc.png")
  );

  auto material = ParticleSystemMaterial::create(
    Material::Parameters().add( "size", 35.f )
                          .add( "map", sprite )
                          .add( "sizeAttenuation", false )
                          .add( "transparent", true)
  );
  material->color.setHSL( 1.f, 0.3f, 0.7f );

  auto particles = ParticleSystem::create( geometry, material );
  particles->sortParticles = true;
  scene->add( particles );

  /////////////////////////////////////////////////////////////////////////

  auto mouseX = 0.f, mouseY = 0.f;
  window.addEventListener( SDL_MOUSEMOTION, [&]( const SDL_Event& event ) {
    mouseX = 2.f * ( ( float )event.motion.x / renderer.width()  - 0.5f );
    mouseY = 2.f * ( ( float )event.motion.y / renderer.height() - 0.5f );
  } );

  window.addEventListener( SDL_WINDOWEVENT, [&]( const SDL_Event& event ) {
    if (event.window.event != SDL_WINDOWEVENT_RESIZED) return;
    camera->aspect = ( float )event.window.data1 / event.window.data2;
    camera->updateProjectionMatrix();
    renderer.setSize( event.window.data1, event.window.data2 );
  } );

  /////////////////////////////////////////////////////////////////////////

  auto time = 0.f;

  window.animate( [&]( float dt ) -> bool {

    time += dt * .05f;

    camera->position().x += ( -1000.f * mouseX - camera->position().x ) * 3 * dt;
    camera->position().y += (  1000.f * mouseY - camera->position().y ) * 3 * dt;
    camera->lookAt( scene->position() );

    const auto h = Math::fmod( 360.f * ( 1.f + time ), 360.f ) / 360.f;
    material->color.setHSL( h, 0.5f, 0.5f );

    renderer.render( *scene, *camera );

    return true;

  } );

}