Esempio n. 1
0
void GLMeshRenderer::DrawLightModel(int arraySize, float deltaSecond, Matrix4x4 perspectiveMatrix, Matrix4x4 viewMatrix, Matrix4x4 modelMatrix, Vector3 lPosition, Vector3 cameraPosition)
{
	//////////////////////////////////////////////////////////////////////////
	arraySize;
	static float totalTime = 0;
	totalTime += deltaSecond;
	glUseProgram(m_material.m_program.m_gProgram);
	GLCheckError(__FILE__, __LINE__);
	glBindVertexArray(m_VAO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_mesh.m_iboID);
	Vector3 cam_position = cameraPosition;
	Vector3 lightPosition = lPosition;
	float light_power = 10000.1f;
	Vector4 ambient_light(1.0f, 1.0f, 1.0f, 0.05f);
	Vector4 light_color(1.0f, 1.0f, 1.0f, light_power);
	GLint textureIndex = 0;
	GLuint m_gBuffer = m_material.m_program.m_gProgram;
	ProgramBindSamplerIndex(m_gBuffer, "gTexDiffuse", textureIndex);
	ProgramBindSamplerIndex(m_gBuffer, "gTexNormal", textureIndex + 1);
	ProgramBindSamplerIndex(m_gBuffer, "gTexSpecGlossEmit", textureIndex + 2);
	ProgramBindMatrix(m_gBuffer, "gProj", perspectiveMatrix);
	ProgramBindMatrix(m_gBuffer, "gView", viewMatrix);
	ProgramBindMatrix(m_gBuffer, "gModel", modelMatrix);
	ProgramBindVector4(m_gBuffer, "gAmbientLight", ambient_light);
	ProgramBindVector4(m_gBuffer, "gLightColor", light_color);
	ProgramBindVector3(m_gBuffer, "gLightPosition", lightPosition);
	ProgramBindVector3(m_gBuffer, "gCameraPosition", cam_position);

	if (m_material.m_sampler.gTexDiffuse == nullptr)
	{
		unsigned char defaultWhiteTexel[3] = { 255, 255, 255 };
		m_material.m_sampler.gTexDiffuse = Texture::CreateMissingTexture("DefaultDiffuse", defaultWhiteTexel, Vector2(1.0f, 1.0f), 3);
	}
	ProgramBindTexture(textureIndex, m_material.m_sampler.gTexDiffuse->GetPlatformHandle());
	textureIndex++;

	if (m_material.m_sampler.gTexNormal == nullptr)
	{
		unsigned char defaultBlueTexel[3] = { 127, 127, 255 };
		m_material.m_sampler.gTexNormal = Texture::CreateMissingTexture("DefaultNormal", defaultBlueTexel, Vector2(1.0f, 1.0f), 3);
	}
	ProgramBindTexture(textureIndex, m_material.m_sampler.gTexNormal->GetPlatformHandle());
	textureIndex++;

	if (m_material.m_sampler.gTexSpecGlossEmit == nullptr)
	{
		unsigned char defaultYellowTexel[3] = { 127, 127, 0 };
		m_material.m_sampler.gTexSpecGlossEmit = Texture::CreateMissingTexture("DefaultSpecGlossEmit", defaultYellowTexel, Vector2(1.0f, 1.0f), 3);
	}
	ProgramBindTexture(textureIndex, m_material.m_sampler.gTexSpecGlossEmit->GetPlatformHandle());

	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	//glDrawArrays(GL_TRIANGLES, 0, m_mesh.m_vboNumBytes);
	glDrawElements(GL_TRIANGLES,m_mesh.m_iboNumIndexes , GL_UNSIGNED_INT,(void*)0 );
	glBindVertexArray(NULL);
	glUseProgram(NULL);
	GLCheckError(__FILE__, __LINE__);

}
Esempio n. 2
0
static void color_light(Widget w, XtPointer data, XmAnyCallbackStruct *cbs)
{
  extern Color *light_color(); /* in clights.c */

  ui_config_colorpanel("Light Color", light_color(), LIGHTINDEX,
			DRAWER_LIGHTCOLOR, 0);
  ui_showpanel(P_COLOR, 1);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRLookUpLight::LightVertex(const MLRVertexData& vertexData)
{
	UnitVector3D light_z;

	GetInShapeDirection(light_z);

	const Scalar One_Over_255 = 1.f/255.0f;

	Point3D worldPoint;

	worldPoint.Multiply(*(vertexData.point), shapeToWorld);

	Scalar prep_x = mapZoneCountX*zoneSizeX - worldPoint.x + mapOrigin.x;
	Scalar prep_z = mapZoneCountZ*zoneSizeZ - worldPoint.z + mapOrigin.z;

	int map_x = Truncate_Float_To_Word(prep_x*one_Over_zoneSizeX);
	int map_z = Truncate_Float_To_Word(prep_z*one_Over_zoneSizeZ);
	Verify(map_x>=0 && map_x<mapZoneCountX);
	Verify(map_z>=0 && map_z<mapZoneCountZ);

	int off_x = Truncate_Float_To_Word((prep_x - map_x*zoneSizeX)*256.0f*one_Over_zoneSizeX);
	int off_z = Truncate_Float_To_Word((prep_z - map_z*zoneSizeZ)*256.0f*one_Over_zoneSizeZ);
	Verify(off_x>=0 && off_x < 256);
	Verify(off_z>=0 && off_z < 256);

	Scalar mapIntensity = maps[map_z*mapZoneCountX+map_x][(off_z<<8)+off_x]*One_Over_255;

	//
	//-------------------------------------------------------------------
	// Now we reduce the light level falling on the vertex based upon the
	// cosine of the angle between light and normal
	//-------------------------------------------------------------------
	//
	Scalar cosine = -(light_z * (*vertexData.normal))*mapIntensity*intensity;



#if COLOR_AS_DWORD
	TO_DO;
#else	// COLOR_AS_DWORD
	RGBColor light_color(color);

	if (cosine > SMALL)
	{
		light_color.red *= cosine;
		light_color.green *= cosine;
		light_color.blue *= cosine;

		vertexData.color->red += light_color.red;
		vertexData.color->green += light_color.green;
		vertexData.color->blue += light_color.blue;
	}
#endif	// COLOR_AS_DWORD
}
Esempio n. 4
0
  /**
   * Renders the AbstractAirspace on the canvas
   * @param as AbstractAirspace to render
   */
  void
  Render(const AbstractAirspace& as)
  {
    int type = as.get_type();
    if (type <= 0)
      return;

    // No intersections for this airspace
    if (m_intersections.empty())
      return;

    // Select pens and brushes
#ifdef ENABLE_SDL
    Color color =
      Graphics::GetAirspaceColour(settings.colours[type]);
#ifdef ENABLE_OPENGL
    color = color.with_alpha(48);
#endif
    Brush brush(color);
#else
    const Brush &brush = Graphics::GetAirspaceBrushByClass(type, settings);
    canvas.set_text_color(light_color(Graphics::GetAirspaceColourByClass(type, settings)));
#endif

    PixelRect rcd;
    // Calculate top and bottom coordinate
    rcd.top = chart.screenY(as.get_top_altitude(state));
    if (as.is_base_terrain())
      rcd.bottom = chart.screenY(fixed_zero);
    else
      rcd.bottom = chart.screenY(as.get_base_altitude(state));

    // Iterate through the intersections
    for (AirspaceIntersectionVector::const_iterator it = m_intersections.begin();
         it != m_intersections.end(); ++it) {
      const GeoPoint p_start = it->first;
      const GeoPoint p_end = it->second;
      const fixed distance_start = start.distance(p_start);
      const fixed distance_end = start.distance(p_end);

      // Determine left and right coordinate
      rcd.left = chart.screenX(distance_start);
      rcd.right = chart.screenX(distance_end);

      // only one edge found, next edge must be beyond screen
      if ((rcd.left == rcd.right) && (p_start == p_end)) {
        rcd.right = chart.screenX(chart.getXmax());
      }

      // Draw the airspace
      RenderBox(rcd, brush, settings.black_outline, type);
    }
  }
Esempio n. 5
0
void GLMeshRenderer::DrawLightShader(int arraySize, float deltaSecond, Matrix4x4 perspectiveMatrix, Matrix4x4 viewMatrix,Matrix4x4 modelMatrix,Vector3 lPosition,Vector3 cameraPosition)
{
	//////////////////////////////////////////////////////////////////////////
	arraySize;
	static float totalTime = 0;
	totalTime += deltaSecond;
	glUseProgram(m_material.m_program.m_gProgram);
	GLCheckError(__FILE__, __LINE__);
	glBindVertexArray(m_VAO);
	Vector3 cam_position = cameraPosition;
	Vector3 lightPosition = lPosition;
	float light_power = 2.1f;
	Vector4 ambient_light(1.0f, 1.0f, 1.0f, 0.05f);
	Vector4 light_color(1.0f, 1.0f, 1.0f, light_power);
	GLint textureIndex = 0;
	GLuint m_gBuffer = m_material.m_program.m_gProgram;
	ProgramBindSamplerIndex(m_gBuffer, "gTexDiffuse", textureIndex);
	ProgramBindSamplerIndex(m_gBuffer, "gTexNormal", textureIndex+1);
	ProgramBindSamplerIndex(m_gBuffer, "gTexSpecular", textureIndex + 2);
	ProgramBindSamplerIndex(m_gBuffer, "gTexEmissive", textureIndex + 3);
	ProgramBindMatrix(m_gBuffer, "gProj", perspectiveMatrix);
	ProgramBindMatrix(m_gBuffer, "gView", viewMatrix);
	ProgramBindMatrix(m_gBuffer, "gModel", modelMatrix);
	ProgramBindVector4(m_gBuffer, "gAmbientLight", ambient_light);
	ProgramBindVector4(m_gBuffer, "gLightColor", light_color);
	ProgramBindVector3(m_gBuffer, "gLightPosition", lightPosition);
	ProgramBindVector3(m_gBuffer, "gCameraPosition", cam_position);
	
	ProgramBindTexture(textureIndex, m_material.m_sampler.gTexDiffuse->GetPlatformHandle());
	textureIndex++;
	ProgramBindTexture(textureIndex, m_material.m_sampler.gTexNormal->GetPlatformHandle());
	textureIndex++;
	ProgramBindTexture(textureIndex, m_material.m_sampler.gTexSpecular->GetPlatformHandle());
	textureIndex++;
	ProgramBindTexture(textureIndex, m_material.m_sampler.gTexEmissive->GetPlatformHandle());
	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	glDrawArrays(GL_TRIANGLES, 0, m_mesh.m_vboNumBytes);
	glBindVertexArray(NULL);
	glUseProgram(NULL);
	GLCheckError(__FILE__, __LINE__);

}
Esempio n. 6
0
void
Graphics::Initialise()
{
  /// @todo enhancement: support red/green color blind pilots with adjusted colour scheme

  LogStartUp(_T("Initialise graphics"));

  LoadUnitSymbols();

  hTerrainWarning.load_big(IDB_TERRAINWARNING, IDB_TERRAINWARNING_HD);
  hGPSStatus1.load_big(IDB_GPSSTATUS1, IDB_GPSSTATUS1_HD, false);
  hGPSStatus2.load_big(IDB_GPSSTATUS2, IDB_GPSSTATUS2_HD, false);
  hLogger.load_big(IDB_LOGGER, IDB_LOGGER_HD);
  hLoggerOff.load_big(IDB_LOGGEROFF, IDB_LOGGEROFF_HD);

  hCruise.load_big(IDB_CRUISE, IDB_CRUISE_HD, false);
  hClimb.load_big(IDB_CLIMB, IDB_CLIMB_HD, false);
  hFinalGlide.load_big(IDB_FINALGLIDE, IDB_FINALGLIDE_HD, false);
  hAbort.load_big(IDB_ABORT, IDB_ABORT_HD, false);

#ifdef HAVE_HATCHED_BRUSH
  hAboveTerrainBitmap.load(IDB_ABOVETERRAIN);

  hAboveTerrainBrush.set(hAboveTerrainBitmap);
#endif

  hpWind.set(Layout::Scale(1), dark_color(COLOR_GRAY));
  hpWindTail.set(Pen::DASH, 1, COLOR_BLACK);
  hbWind.set(COLOR_GRAY);

  hBmpMapScaleLeft.load_big(IDB_MAPSCALE_LEFT, IDB_MAPSCALE_LEFT_HD, false);
  hBmpMapScaleRight.load_big(IDB_MAPSCALE_RIGHT, IDB_MAPSCALE_RIGHT_HD, false);

  hBmpTabTask.load((Layout::scale > 1) ? IDB_TASK_HD : IDB_TASK);
  hBmpTabWrench.load((Layout::scale > 1) ? IDB_WRENCH_HD : IDB_WRENCH);
  hBmpTabSettings.load((Layout::scale > 1) ? IDB_SETTINGS_HD : IDB_SETTINGS);
  hBmpTabCalculator.load((Layout::scale > 1) ? IDB_CALCULATOR_HD : IDB_CALCULATOR);

  hBmpTabFlight.load((Layout::scale > 1) ? IDB_GLOBE_HD : IDB_GLOBE);
  hBmpTabSystem.load((Layout::scale > 1) ? IDB_DEVICE_HD : IDB_DEVICE);
  hBmpTabRules.load((Layout::scale > 1) ? IDB_RULES_HD : IDB_RULES);
  hBmpTabTimes.load((Layout::scale > 1) ? IDB_CLOCK_HD : IDB_CLOCK);

  hBmpThermalSource.load_big(IDB_THERMALSOURCE, IDB_THERMALSOURCE_HD);

  hBmpTrafficSafe.load_big(IDB_TRAFFIC_SAFE, IDB_TRAFFIC_SAFE_HD, false);
  hBmpTrafficWarning.load_big(IDB_TRAFFIC_WARNING, IDB_TRAFFIC_WARNING_HD, false);
  hBmpTrafficAlarm.load_big(IDB_TRAFFIC_ALARM, IDB_TRAFFIC_ALARM_HD, false);

  hbCompass.set(Color(207, 207, 207));

  hbFinalGlideBelow.set(COLOR_RED);
  hpFinalGlideBelow.set(Layout::Scale(1), dark_color(COLOR_RED));

  hbFinalGlideBelowLandable.set(COLOR_ORANGE);
  hpFinalGlideBelowLandable.set(Layout::Scale(1), dark_color(COLOR_ORANGE));

  hbFinalGlideAbove.set(COLOR_GREEN);
  hpFinalGlideAbove.set(Layout::Scale(1), dark_color(COLOR_GREEN));

  hpCompass.set(Layout::Scale(1), COLOR_GRAY);

  hpMapScale.set(Layout::Scale(1), COLOR_BLACK);

  hpTerrainLine.set(Pen::DASH, Layout::Scale(1), clrSepia);
  hpTerrainLineThick.set(Pen::DASH, Layout::Scale(2), clrSepia);

  TracePen.set(2, Color(50, 243, 45));
  ContestPen[0].set(Layout::Scale(1)+2, COLOR_RED);
  ContestPen[1].set(Layout::Scale(1)+1, COLOR_ORANGE);
  ContestPen[2].set(Layout::Scale(1), COLOR_BLUE);

    // used for landable rendering
  hbGreen.set(COLOR_GREEN);
  hbWhite.set(COLOR_WHITE);
  hbOrange.set(COLOR_ORANGE);
  hbLightGray.set(COLOR_LIGHT_GRAY);
  hbNotReachableTerrain.set(light_color(COLOR_RED));

  hbGround.set(GroundColor);

  hpTrackBearingLine.set(3, COLOR_GRAY);
}
Esempio n. 7
0
	virtual void updateTexturesAndMeshes(IGameDef *gamedef)
	{
#ifndef SERVER
		infostream<<"ItemDefManager::updateTexturesAndMeshes(): Updating "
				<<"textures and meshes in item definitions"<<std::endl;

		ITextureSource *tsrc = gamedef->getTextureSource();
		INodeDefManager *nodedef = gamedef->getNodeDefManager();
		IrrlichtDevice *device = tsrc->getDevice();
		video::IVideoDriver *driver = device->getVideoDriver();

		for(std::map<std::string, ItemDefinition*>::iterator
				i = m_item_definitions.begin();
				i != m_item_definitions.end(); i++)
		{
			ItemDefinition *def = i->second;

			bool need_node_mesh = false;

			// Create an inventory texture
			def->inventory_texture = NULL;
			if(def->inventory_image != "")
			{
				def->inventory_texture = tsrc->getTextureRaw(def->inventory_image);
			}
			else if(def->type == ITEM_NODE)
			{
				need_node_mesh = true;
			}

			// Create a wield mesh
			if(def->wield_mesh != NULL)
			{
				def->wield_mesh->drop();
				def->wield_mesh = NULL;
			}
			if(def->type == ITEM_NODE && def->wield_image == "")
			{
				need_node_mesh = true;
			}
			else if(def->wield_image != "" || def->inventory_image != "")
			{
				// Extrude the wield image into a mesh

				std::string imagename;
				if(def->wield_image != "")
					imagename = def->wield_image;
				else
					imagename = def->inventory_image;

				def->wield_mesh = createExtrudedMesh(
						tsrc->getTextureRaw(imagename),
						driver,
						def->wield_scale * v3f(40.0, 40.0, 4.0));
				if(def->wield_mesh == NULL)
				{
					infostream<<"ItemDefManager: WARNING: "
						<<"updateTexturesAndMeshes(): "
						<<"Unable to create extruded mesh for item "
						<<def->name<<std::endl;
				}
			}

			if(need_node_mesh)
			{
				/*
					Get node properties
				*/
				content_t id = nodedef->getId(def->name);
				const ContentFeatures &f = nodedef->get(id);

				u8 param1 = 0;
				if(f.param_type == CPT_LIGHT)
					param1 = 0xee;

				/*
				 	Make a mesh from the node
				*/
				MeshMakeData mesh_make_data(gamedef);
				MapNode mesh_make_node(id, param1, 0);
				mesh_make_data.fillSingleNode(&mesh_make_node);
				MapBlockMesh mapblock_mesh(&mesh_make_data);

				scene::IMesh *node_mesh = mapblock_mesh.getMesh();
				assert(node_mesh);
				setMeshColor(node_mesh, video::SColor(255, 255, 255, 255));

				/*
					Scale and translate the mesh so it's a unit cube
					centered on the origin
				*/
				scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS));
				translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0));

				/*
					Draw node mesh into a render target texture
				*/
				if(def->inventory_texture == NULL)
				{
					core::dimension2d<u32> dim(64,64);
					std::string rtt_texture_name = "INVENTORY_"
						+ def->name + "_RTT";
					v3f camera_position(0, 1.0, -1.5);
					camera_position.rotateXZBy(45);
					v3f camera_lookat(0, 0, 0);
					core::CMatrix4<f32> camera_projection_matrix;
					// Set orthogonal projection
					camera_projection_matrix.buildProjectionMatrixOrthoLH(
							1.65, 1.65, 0, 100);

					video::SColorf ambient_light(0.2,0.2,0.2);
					v3f light_position(10, 100, -50);
					video::SColorf light_color(0.5,0.5,0.5);
					f32 light_radius = 1000;

					def->inventory_texture = generateTextureFromMesh(
						node_mesh, device, dim, rtt_texture_name,
						camera_position,
						camera_lookat,
						camera_projection_matrix,
						ambient_light,
						light_position,
						light_color,
						light_radius);

					// render-to-target didn't work
					if(def->inventory_texture == NULL)
					{
						def->inventory_texture =
							tsrc->getTextureRaw(f.tname_tiles[0]);
					}
				}

				/*
					Use the node mesh as the wield mesh
				*/
				if(def->wield_mesh == NULL)
				{
					// Scale to proper wield mesh proportions
					scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0)
							* def->wield_scale);
					def->wield_mesh = node_mesh;
					def->wield_mesh->grab();
				}

				// falling outside of here deletes node_mesh
			}
		}
#endif
	}
Esempio n. 8
0
bool generate_image(std::string part_of_name, video::IImage *& baseimg,
		IrrlichtDevice *device, SourceImageCache *sourcecache)
{
	video::IVideoDriver* driver = device->getVideoDriver();
	assert(driver);

	// Stuff starting with [ are special commands
	if(part_of_name.size() == 0 || part_of_name[0] != '[')
	{
		video::IImage *image = sourcecache->getOrLoad(part_of_name, device);

		if(image == NULL)
		{
			if(part_of_name != ""){
				errorstream<<"generate_image(): Could not load image \""
						<<part_of_name<<"\""<<" while building texture"<<std::endl;
				errorstream<<"generate_image(): Creating a dummy"
						<<" image for \""<<part_of_name<<"\""<<std::endl;
			}

			// Just create a dummy image
			//core::dimension2d<u32> dim(2,2);
			core::dimension2d<u32> dim(1,1);
			image = driver->createImage(video::ECF_A8R8G8B8, dim);
			assert(image);
			/*image->setPixel(0,0, video::SColor(255,255,0,0));
			image->setPixel(1,0, video::SColor(255,0,255,0));
			image->setPixel(0,1, video::SColor(255,0,0,255));
			image->setPixel(1,1, video::SColor(255,255,0,255));*/
			image->setPixel(0,0, video::SColor(255,myrand()%256,
					myrand()%256,myrand()%256));
			/*image->setPixel(1,0, video::SColor(255,myrand()%256,
					myrand()%256,myrand()%256));
			image->setPixel(0,1, video::SColor(255,myrand()%256,
					myrand()%256,myrand()%256));
			image->setPixel(1,1, video::SColor(255,myrand()%256,
					myrand()%256,myrand()%256));*/
		}

		// If base image is NULL, load as base.
		if(baseimg == NULL)
		{
			//infostream<<"Setting "<<part_of_name<<" as base"<<std::endl;
			/*
				Copy it this way to get an alpha channel.
				Otherwise images with alpha cannot be blitted on 
				images that don't have alpha in the original file.
			*/
			core::dimension2d<u32> dim = image->getDimension();
			baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
			image->copyTo(baseimg);
			image->drop();
		}
		// Else blit on base.
		else
		{
			//infostream<<"Blitting "<<part_of_name<<" on base"<<std::endl;
			// Size of the copied area
			core::dimension2d<u32> dim = image->getDimension();
			//core::dimension2d<u32> dim(16,16);
			// Position to copy the blitted to in the base image
			core::position2d<s32> pos_to(0,0);
			// Position to copy the blitted from in the blitted image
			core::position2d<s32> pos_from(0,0);
			// Blit
			image->copyToWithAlpha(baseimg, pos_to,
					core::rect<s32>(pos_from, dim),
					video::SColor(255,255,255,255),
					NULL);
			// Drop image
			image->drop();
		}
	}
	else
	{
		// A special texture modification

		/*infostream<<"generate_image(): generating special "
				<<"modification \""<<part_of_name<<"\""
				<<std::endl;*/
		
		/*
			This is the simplest of all; it just adds stuff to the
			name so that a separate texture is created.

			It is used to make textures for stuff that doesn't want
			to implement getting the texture from a bigger texture
			atlas.
		*/
		if(part_of_name == "[forcesingle")
		{
			// If base image is NULL, create a random color
			if(baseimg == NULL)
			{
				core::dimension2d<u32> dim(1,1);
				baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
				assert(baseimg);
				baseimg->setPixel(0,0, video::SColor(255,myrand()%256,
						myrand()%256,myrand()%256));
			}
		}
		/*
			[crackN
			Adds a cracking texture
		*/
		else if(part_of_name.substr(0,6) == "[crack")
		{
			if(baseimg == NULL)
			{
				errorstream<<"generate_image(): baseimg==NULL "
						<<"for part_of_name=\""<<part_of_name
						<<"\", cancelling."<<std::endl;
				return false;
			}
			
			// Crack image number and overlay option
			s32 progression = 0;
			bool use_overlay = false;
			if(part_of_name.substr(6,1) == "o")
			{
				progression = stoi(part_of_name.substr(7));
				use_overlay = true;
			}
			else
			{
				progression = stoi(part_of_name.substr(6));
				use_overlay = false;
			}

			// Size of the base image
			core::dimension2d<u32> dim_base = baseimg->getDimension();
			
			/*
				Load crack image.

				It is an image with a number of cracking stages
				horizontally tiled.
			*/
			video::IImage *img_crack = sourcecache->getOrLoad("crack.png", device);
		
			if(img_crack && progression >= 0)
			{
				// Dimension of original image
				core::dimension2d<u32> dim_crack
						= img_crack->getDimension();
				// Count of crack stages
				s32 crack_count = dim_crack.Height / dim_crack.Width;
				// Limit progression
				if(progression > crack_count-1)
					progression = crack_count-1;
				// Dimension of a single crack stage
				core::dimension2d<u32> dim_crack_cropped(
					dim_crack.Width,
					dim_crack.Width
				);
				// Create cropped and scaled crack images
				video::IImage *img_crack_cropped = driver->createImage(
						video::ECF_A8R8G8B8, dim_crack_cropped);
				video::IImage *img_crack_scaled = driver->createImage(
						video::ECF_A8R8G8B8, dim_base);

				if(img_crack_cropped && img_crack_scaled)
				{
					// Crop crack image
					v2s32 pos_crack(0, progression*dim_crack.Width);
					img_crack->copyTo(img_crack_cropped,
							v2s32(0,0),
							core::rect<s32>(pos_crack, dim_crack_cropped));
					// Scale crack image by copying
					img_crack_cropped->copyToScaling(img_crack_scaled);
					// Copy or overlay crack image
					if(use_overlay)
					{
						overlay(baseimg, img_crack_scaled);
					}
					else
					{
						img_crack_scaled->copyToWithAlpha(
								baseimg,
								v2s32(0,0),
								core::rect<s32>(v2s32(0,0), dim_base),
								video::SColor(255,255,255,255));
					}
				}

				if(img_crack_scaled)
					img_crack_scaled->drop();

				if(img_crack_cropped)
					img_crack_cropped->drop();
				
				img_crack->drop();
			}
		}
		/*
			[combine:WxH:X,Y=filename:X,Y=filename2
			Creates a bigger texture from an amount of smaller ones
		*/
		else if(part_of_name.substr(0,8) == "[combine")
		{
			Strfnd sf(part_of_name);
			sf.next(":");
			u32 w0 = stoi(sf.next("x"));
			u32 h0 = stoi(sf.next(":"));
			infostream<<"combined w="<<w0<<" h="<<h0<<std::endl;
			core::dimension2d<u32> dim(w0,h0);
			baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
			while(sf.atend() == false)
			{
				u32 x = stoi(sf.next(","));
				u32 y = stoi(sf.next("="));
				std::string filename = sf.next(":");
				infostream<<"Adding \""<<filename
						<<"\" to combined ("<<x<<","<<y<<")"
						<<std::endl;
				video::IImage *img = sourcecache->getOrLoad(filename, device);
				if(img)
				{
					core::dimension2d<u32> dim = img->getDimension();
					infostream<<"Size "<<dim.Width
							<<"x"<<dim.Height<<std::endl;
					core::position2d<s32> pos_base(x, y);
					video::IImage *img2 =
							driver->createImage(video::ECF_A8R8G8B8, dim);
					img->copyTo(img2);
					img->drop();
					img2->copyToWithAlpha(baseimg, pos_base,
							core::rect<s32>(v2s32(0,0), dim),
							video::SColor(255,255,255,255),
							NULL);
					img2->drop();
				}
				else
				{
					infostream<<"img==NULL"<<std::endl;
				}
			}
		}
		/*
			"[brighten"
		*/
		else if(part_of_name.substr(0,9) == "[brighten")
		{
			if(baseimg == NULL)
			{
				errorstream<<"generate_image(): baseimg==NULL "
						<<"for part_of_name=\""<<part_of_name
						<<"\", cancelling."<<std::endl;
				return false;
			}

			brighten(baseimg);
		}
		/*
			"[noalpha"
			Make image completely opaque.
			Used for the leaves texture when in old leaves mode, so
			that the transparent parts don't look completely black 
			when simple alpha channel is used for rendering.
		*/
		else if(part_of_name.substr(0,8) == "[noalpha")
		{
			if(baseimg == NULL)
			{
				errorstream<<"generate_image(): baseimg==NULL "
						<<"for part_of_name=\""<<part_of_name
						<<"\", cancelling."<<std::endl;
				return false;
			}

			core::dimension2d<u32> dim = baseimg->getDimension();
			
			// Set alpha to full
			for(u32 y=0; y<dim.Height; y++)
			for(u32 x=0; x<dim.Width; x++)
			{
				video::SColor c = baseimg->getPixel(x,y);
				c.setAlpha(255);
				baseimg->setPixel(x,y,c);
			}
		}
		/*
			"[makealpha:R,G,B"
			Convert one color to transparent.
		*/
		else if(part_of_name.substr(0,11) == "[makealpha:")
		{
			if(baseimg == NULL)
			{
				errorstream<<"generate_image(): baseimg==NULL "
						<<"for part_of_name=\""<<part_of_name
						<<"\", cancelling."<<std::endl;
				return false;
			}

			Strfnd sf(part_of_name.substr(11));
			u32 r1 = stoi(sf.next(","));
			u32 g1 = stoi(sf.next(","));
			u32 b1 = stoi(sf.next(""));
			std::string filename = sf.next("");

			core::dimension2d<u32> dim = baseimg->getDimension();
			
			/*video::IImage *oldbaseimg = baseimg;
			baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
			oldbaseimg->copyTo(baseimg);
			oldbaseimg->drop();*/

			// Set alpha to full
			for(u32 y=0; y<dim.Height; y++)
			for(u32 x=0; x<dim.Width; x++)
			{
				video::SColor c = baseimg->getPixel(x,y);
				u32 r = c.getRed();
				u32 g = c.getGreen();
				u32 b = c.getBlue();
				if(!(r == r1 && g == g1 && b == b1))
					continue;
				c.setAlpha(0);
				baseimg->setPixel(x,y,c);
			}
		}
		/*
			[inventorycube{topimage{leftimage{rightimage
			In every subimage, replace ^ with &.
			Create an "inventory cube".
			NOTE: This should be used only on its own.
			Example (a grass block (not actually used in game):
			"[inventorycube{grass.png{mud.png&grass_side.png{mud.png&grass_side.png"
		*/
		else if(part_of_name.substr(0,14) == "[inventorycube")
		{
			if(baseimg != NULL)
			{
				errorstream<<"generate_image(): baseimg!=NULL "
						<<"for part_of_name=\""<<part_of_name
						<<"\", cancelling."<<std::endl;
				return false;
			}

			str_replace_char(part_of_name, '&', '^');
			Strfnd sf(part_of_name);
			sf.next("{");
			std::string imagename_top = sf.next("{");
			std::string imagename_left = sf.next("{");
			std::string imagename_right = sf.next("{");

			// Generate images for the faces of the cube
			video::IImage *img_top = generate_image_from_scratch(
					imagename_top, device, sourcecache);
			video::IImage *img_left = generate_image_from_scratch(
					imagename_left, device, sourcecache);
			video::IImage *img_right = generate_image_from_scratch(
					imagename_right, device, sourcecache);
			assert(img_top && img_left && img_right);

			// Create textures from images
			video::ITexture *texture_top = driver->addTexture(
					(imagename_top + "__temp__").c_str(), img_top);
			video::ITexture *texture_left = driver->addTexture(
					(imagename_left + "__temp__").c_str(), img_left);
			video::ITexture *texture_right = driver->addTexture(
					(imagename_right + "__temp__").c_str(), img_right);
			assert(texture_top && texture_left && texture_right);

			// Drop images
			img_top->drop();
			img_left->drop();
			img_right->drop();
			
			/*
				Draw a cube mesh into a render target texture
			*/
			scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1));
			setMeshColor(cube, video::SColor(255, 255, 255, 255));
			cube->getMeshBuffer(0)->getMaterial().setTexture(0, texture_top);
			cube->getMeshBuffer(1)->getMaterial().setTexture(0, texture_top);
			cube->getMeshBuffer(2)->getMaterial().setTexture(0, texture_right);
			cube->getMeshBuffer(3)->getMaterial().setTexture(0, texture_right);
			cube->getMeshBuffer(4)->getMaterial().setTexture(0, texture_left);
			cube->getMeshBuffer(5)->getMaterial().setTexture(0, texture_left);

			core::dimension2d<u32> dim(64,64);
			std::string rtt_texture_name = part_of_name + "_RTT";

			v3f camera_position(0, 1.0, -1.5);
			camera_position.rotateXZBy(45);
			v3f camera_lookat(0, 0, 0);
			core::CMatrix4<f32> camera_projection_matrix;
			// Set orthogonal projection
			camera_projection_matrix.buildProjectionMatrixOrthoLH(
					1.65, 1.65, 0, 100);

			video::SColorf ambient_light(0.2,0.2,0.2);
			v3f light_position(10, 100, -50);
			video::SColorf light_color(0.5,0.5,0.5);
			f32 light_radius = 1000;

			video::ITexture *rtt = generateTextureFromMesh(
					cube, device, dim, rtt_texture_name,
					camera_position,
					camera_lookat,
					camera_projection_matrix,
					ambient_light,
					light_position,
					light_color,
					light_radius);
			
			// Drop mesh
			cube->drop();

			// Free textures of images
			driver->removeTexture(texture_top);
			driver->removeTexture(texture_left);
			driver->removeTexture(texture_right);
			
			if(rtt == NULL)
			{
				baseimg = generate_image_from_scratch(
						imagename_top, device, sourcecache);
				return true;
			}

			// Create image of render target
			video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
			assert(image);

			baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);

			if(image)
			{
				image->copyTo(baseimg);
				image->drop();
			}
		}
		else
		{
			errorstream<<"generate_image(): Invalid "
					" modification: \""<<part_of_name<<"\""<<std::endl;
		}
	}

	return true;
}
Esempio n. 9
0
void MainWindow::render()
{
    glViewport(0, 0, width(), height());

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    m_program->bind();


//    GLfloat colors[] = {
//        1.0f, 0.0f, 0.0f,
//        0.0f, 1.0f, 0.0f,
//        0.0f, 0.0f, 1.0f
//    };


    now = clock();
    m_frame = m_frame + speed*difftime(now, lastTime);
    lastTime = now;


    // Planet Matrix
    scale.scale(4.0f);
    rotMatrix.rotate(m_frame * 0.2, 0, 1, 0);
    cg::Planet sonne("sonne", &myMesh->v[0], scale, rotMatrix, orbitMatrix, orbitRotMatrix);

    scale.setToIdentity();
    orbitRotMatrix.setToIdentity();
    orbitMatrix.setToIdentity();
    rotMatrix.setToIdentity();
    scale.scale(0.5f);
    orbitRotMatrix.rotate(m_frame, 0, 1, 0);
    orbitMatrix.translate(5.0f, 0, 0);
    rotMatrix.rotate(m_frame, 0, 1, 0);
    cg::Planet erde("erde", &myMesh->v[0], scale, rotMatrix, orbitMatrix, orbitRotMatrix);

    scale.setToIdentity();
    orbitRotMatrix.setToIdentity();
    orbitMatrix.setToIdentity();
    rotMatrix.setToIdentity();
    scale.scale(0.3f);
    orbitRotMatrix.rotate(m_frame, 0, 1, 0);
    orbitMatrix.translate(1.0f, 0, 0);
    rotMatrix.rotate(m_frame, 0, 1, 0);
    cg::Planet mond("mond", &myMesh->v[0], scale, rotMatrix, orbitMatrix, orbitRotMatrix);

    scale.setToIdentity();
    orbitRotMatrix.setToIdentity();
    orbitMatrix.setToIdentity();
    rotMatrix.setToIdentity();
    scale.scale(0.5f);
    orbitRotMatrix.rotate(0.5 * m_frame + 15, 0, 1, 0);
    orbitMatrix.translate(10.0f, 0, 0);
    rotMatrix.rotate(m_frame, 0, 1, 0);
    cg::Planet mars("mars", &myMesh->v[0], scale, rotMatrix, orbitMatrix, orbitRotMatrix);

    scale.setToIdentity();
    orbitRotMatrix.setToIdentity();
    orbitMatrix.setToIdentity();
    rotMatrix.setToIdentity();
    scale.scale(0.3f);
    orbitRotMatrix.rotate(m_frame, 0, 1, 0);
    orbitMatrix.translate(1.0f, 0, 0);
    rotMatrix.rotate(m_frame, 0, 1, 0);
    cg::Planet deimos("deimos", &myMesh->v[0], scale, rotMatrix, orbitMatrix, orbitRotMatrix);

    scale.setToIdentity();
    orbitRotMatrix.setToIdentity();
    orbitMatrix.setToIdentity();
    rotMatrix.setToIdentity();
    scale.scale(0.15f);
    orbitRotMatrix.rotate(m_frame *15, 0, 1, 0);
    orbitMatrix.translate(1.0f, 0, 0);
    rotMatrix.rotate(m_frame, 0, 1, 0);
    cg::Planet phobos("phobos", &myMesh->v[0], scale, rotMatrix, orbitMatrix, orbitRotMatrix);

    std::vector<cg::Planet*> vecPlanet {&sonne, &erde, &mond, &mars, &deimos, &phobos};
    cg::Sunsystem sys;
    sys.addChild(&sonne)->addChild(&erde)->addChild(&mond);
    sys.addChild(&mars)->addChild(&deimos);
    sys.getChild(1)->addChild(&phobos);
    sys.run();


    projMatrix.setToIdentity();
    //projMatrix.perspective(60.f, 4.0f/3.0f, 0.1f, 100.0f);
    projMatrix.perspective(60.f, width()/height(), 0.1f, 100.0f);
    viewMatrix.setToIdentity();
    viewMatrix.translate(0, 0, -15);
    viewMatrix.rotate(45, 1, 0, 0);


    QVector3D ambient(0.2, 0.2, 0.2);
    QVector3D diffuse_albedo(1.0, 0.88, 0.25);
    QVector3D specular_albedo(1.0, 1.0, 1.0);
    GLfloat specular_power = 128.0;
    QVector3D light_color(0.2, 0.7, 0.2);

    for(cg::Planet* n : vecPlanet)
    {
        m_program->setUniformValue(m_mv_matrix, n->resultmatrix);
        m_program->setUniformValue(m_view_matrix, viewMatrix);
        m_program->setUniformValue(m_proj_matrix, projMatrix);

        m_program->setUniformValue(m_ambient, ambient);
        m_program->setUniformValue(m_diffuse_albedo, diffuse_albedo);
        m_program->setUniformValue(m_specular_albedo, specular_albedo);
        m_program->setUniformValue(m_specular_power, specular_power);


        for(std::vector<GLfloat>& light : lightPositions)
        {
            // Because of QT
            QVector4D lightPosition (light[0], light[1], light[2], light[3]);

            m_program->setUniformValue(m_light, lightPosition);
            m_program->setUniformValue(m_light_color, light_color);
            glDrawElements(GL_TRIANGLES, myMesh->v_f.size(), GL_UNSIGNED_INT, 0);
        }
    }

    m_program->release();

    //Clear Matrices
    scale.setToIdentity();
    orbitRotMatrix.setToIdentity();
    orbitMatrix.setToIdentity();
    rotMatrix.setToIdentity();
}
Esempio n. 10
0
    ClientCached* createClientCachedDirect(const std::string &name,
                                           IGameDef *gamedef) const
    {
        infostream<<"Lazily creating item texture and mesh for \""
                  <<name<<"\""<<std::endl;

        // This is not thread-safe
        assert(get_current_thread_id() == m_main_thread);

        // Skip if already in cache
        ClientCached *cc = NULL;
        m_clientcached.get(name, &cc);
        if(cc)
            return cc;

        ITextureSource *tsrc = gamedef->getTextureSource();
        INodeDefManager *nodedef = gamedef->getNodeDefManager();
        IrrlichtDevice *device = tsrc->getDevice();
        video::IVideoDriver *driver = device->getVideoDriver();
        const ItemDefinition *def = &get(name);

        // Create new ClientCached
        cc = new ClientCached();

        bool need_node_mesh = false;

        // Create an inventory texture
        cc->inventory_texture = NULL;
        if(def->inventory_image != "")
        {
            cc->inventory_texture = tsrc->getTextureRaw(def->inventory_image);
        }
        else if(def->type == ITEM_NODE)
        {
            need_node_mesh = true;
        }

        // Create a wield mesh
        assert(cc->wield_mesh == NULL);
        if(def->type == ITEM_NODE && def->wield_image == "")
        {
            need_node_mesh = true;
        }
        else if(def->wield_image != "" || def->inventory_image != "")
        {
            // Extrude the wield image into a mesh

            std::string imagename;
            if(def->wield_image != "")
                imagename = def->wield_image;
            else
                imagename = def->inventory_image;

            cc->wield_mesh = createExtrudedMesh(
                                 tsrc->getTextureRaw(imagename),
                                 driver,
                                 def->wield_scale * v3f(40.0, 40.0, 4.0));
            if(cc->wield_mesh == NULL)
            {
                infostream<<"ItemDefManager: WARNING: "
                          <<"updateTexturesAndMeshes(): "
                          <<"Unable to create extruded mesh for item "
                          <<def->name<<std::endl;
            }
        }

        if(need_node_mesh)
        {
            /*
            	Get node properties
            */
            content_t id = nodedef->getId(def->name);
            const ContentFeatures &f = nodedef->get(id);

            u8 param1 = 0;
            if(f.param_type == CPT_LIGHT)
                param1 = 0xee;

            /*
            	Make a mesh from the node
            */
            MeshMakeData mesh_make_data(gamedef);
            MapNode mesh_make_node(id, param1, 0);
            mesh_make_data.fillSingleNode(&mesh_make_node);
            MapBlockMesh mapblock_mesh(&mesh_make_data);

            scene::IMesh *node_mesh = mapblock_mesh.getMesh();
            assert(node_mesh);
            video::SColor c(255, 255, 255, 255);
            if(g_settings->getS32("enable_shaders") != 0)
                c = MapBlock_LightColor(255, 0xffff, decode_light(f.light_source));
            setMeshColor(node_mesh, c);

            /*
            	Scale and translate the mesh so it's a unit cube
            	centered on the origin
            */
            scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS));
            translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0));

            /*
            	Draw node mesh into a render target texture
            */
            if(cc->inventory_texture == NULL)
            {
                core::dimension2d<u32> dim(64,64);
                std::string rtt_texture_name = "INVENTORY_"
                                               + def->name + "_RTT";
                v3f camera_position(0, 1.0, -1.5);
                camera_position.rotateXZBy(45);
                v3f camera_lookat(0, 0, 0);
                core::CMatrix4<f32> camera_projection_matrix;
                // Set orthogonal projection
                camera_projection_matrix.buildProjectionMatrixOrthoLH(
                    1.65, 1.65, 0, 100);

                video::SColorf ambient_light(0.2,0.2,0.2);
                v3f light_position(10, 100, -50);
                video::SColorf light_color(0.5,0.5,0.5);
                f32 light_radius = 1000;

                cc->inventory_texture = generateTextureFromMesh(
                                            node_mesh, device, dim, rtt_texture_name,
                                            camera_position,
                                            camera_lookat,
                                            camera_projection_matrix,
                                            ambient_light,
                                            light_position,
                                            light_color,
                                            light_radius);

                // render-to-target didn't work
                if(cc->inventory_texture == NULL)
                {
                    cc->inventory_texture =
                        tsrc->getTextureRaw(f.tiledef[0].name);
                }
            }
            else
            {
                if (m_driver == 0)
                    m_driver = driver;

                m_extruded_textures.push_back(cc->inventory_texture);
            }

            /*
            	Use the node mesh as the wield mesh
            */

            // Scale to proper wield mesh proportions
            scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0)
                      * def->wield_scale);

            cc->wield_mesh = node_mesh;
            cc->wield_mesh->grab();

            //no way reference count can be smaller than 2 in this place!
            assert(cc->wield_mesh->getReferenceCount() >= 2);
        }

        // Put in cache
        m_clientcached.set(name, cc);

        return cc;
    }
Esempio n. 11
0
color_t Shape::phong(const point3d_t p, const point2d_t tc, const point3d_t n, const ray_t *ray) const {
	const World *world = this->world();
	color_t texture = material.texture == 0 ? material.color : material.texture(tc);
	if(!world) return texture;
	boost::numeric::ublas::vector<double> color = vector3d(0.0, 0.0, 0.0);

	boost::numeric::ublas::vector<double> vn = vector3d(n.x, n.y, n.z);
	boost::numeric::ublas::vector<double> vv = vector3d(-ray->d.x, -ray->d.y, -ray->d.z);
	double dvn = dot_prod(vv, vn);
	double nit = 1.0 / material.n;
	if (dvn < 0.0) {
		nit = material.n / 1.0;
		vn = -vn;
		dvn = dot_prod(vv, vn);
	}

	boost::numeric::ublas::vector<double> texture_color = vector3d(texture.r, texture.g, texture.b);
	boost::numeric::ublas::vector<double> specular_color = vector3d(material.specular.r, material.specular.g, material.specular.b);
	boost::numeric::ublas::vector<double> ambient_color = vector3d(world->ambient.r, world->ambient.g, world->ambient.b);

	// ambient
	color += material.ka * vector3d(ambient_color(0) * texture_color(0),
				 ambient_color(1) * texture_color(1),
				 ambient_color(2) * texture_color(2));

	double kr = material.kr;

	// transmission
	if(ray->ttl > 0 && material.kt > 0.0 && material.n > 0.0) {
		double l = 1.0 + nit*nit*(dvn*dvn - 1.0);
		if(l >= 0.0) {
			boost::numeric::ublas::vector<double> d = -nit * vv;
			d += (nit*dvn - sqrt(l)) * vn;
			d = normalize(d);
			ray_t transmission_ray;
			transmission_ray.p = p;
			transmission_ray.d = POINT3D(d(0), d(1), d(2));
			transmission_ray.near = 0.000000001;
			transmission_ray.far = DOUBLE_INF;
			transmission_ray.ttl = ray->ttl-1;
			color_t transmission_color = world->trace(&transmission_ray);
			color += material.kt * vector3d(transmission_color.r, transmission_color.g, transmission_color.b);
		} else
			kr += material.kt;
	}


	// reflection
	if(ray->ttl > 0 && kr > 0.0) {
		boost::numeric::ublas::vector<double> vr = 2.0 * dot_prod(vv, vn) * vn - vv;
		ray_t reflection_ray;
		reflection_ray.p = p;
		reflection_ray.d = POINT3D(vr(0), vr(1), vr(2));
		reflection_ray.near = 0.000001;
		reflection_ray.far = DOUBLE_INF;
		reflection_ray.ttl = ray->ttl-1;
		color_t reflection_color = world->trace(&reflection_ray);
		color += kr * vector3d(reflection_color.r, reflection_color.g, reflection_color.b);
	}

	// lights
	for(std::vector<Light*>::const_iterator i = world->lights.begin(); i != world->lights.end(); i++) {
		// shadow ray
		point3d_t s = (*i)->getSource();
		boost::numeric::ublas::vector<double> vs = vector3d(s.x - p.x, s.y - p.y, s.z - p.z);
		double light_distance = sqrt(dot_prod(vs, vs));
		vs = normalize(vs);
		ray_t shadow_ray;
		shadow_ray.p = p;
		shadow_ray.d = POINT3D(vs(0), vs(1), vs(2));
		shadow_ray.near = 0.00000001;
		shadow_ray.far = DOUBLE_INF;
		shadow_ray.ttl = 1;
		if(world->hit(&shadow_ray).t < light_distance) continue;

		light_t light = (*i)->getLight();
		boost::numeric::ublas::vector<double> light_color = vector3d(light.color.r, light.color.g, light.color.b);
		// diffuse
		color += material.kd * dot_prod(vs, vn) * vector3d(light_color(0) * texture_color(0),
								light_color(1) * texture_color(1),
								light_color(2) * texture_color(2));
		// specular
		boost::numeric::ublas::vector<double> vr = 2.0 * dot_prod(vs, vn) * vn - vs;
		double vra = dot_prod(vr, vv);
		if(vra >= 0.0) color += material.ks * pow(vra, material.ke) * vector3d(light_color(0) * specular_color(0),
							light_color(1) * specular_color(1),
							light_color(2) * specular_color(2));
	}

	// keep color in range
	if(color(0) > 1.0) color(0) = 1.0;
	if(color(0) < 0.0) color(0) = 0.0;
	if(color(1) > 1.0) color(1) = 1.0;
	if(color(1) < 0.0) color(1) = 0.0;
	if(color(2) > 1.0) color(2) = 1.0;
	if(color(2) < 0.0) color(2) = 0.0;
	return COLOR(color(0), color(1), color(2));
}