Пример #1
0
//-- public methods -----
float clampf(float x, float lo, float hi)
{
	return fminf(fmaxf(x, lo), hi);
}
Пример #2
0
 /// clamp each vector values
 Vec3 clamp(const Vec3& min_v, const Vec3& max_v) const {
     return Vec3( fminf( fmaxf(x, min_v.x), max_v.x),
                  fminf( fmaxf(y, min_v.y), max_v.y),
                  fminf( fmaxf(z, min_v.z), max_v.z));
 }
Пример #3
0
void GUIComponent::Render(const CU::Vector2<int>& aWindowSize, const CU::Vector2<float>& aMousePos, bool aIsActiveState)
{
	aMousePos;
	myIsActiveState = aIsActiveState;

	my3DClosestEnemyLength = 10000.f;
	myClosestEnemyLength = 100000.f;
	myClosestEnemy = nullptr;

	Prism::Engine::GetInstance()->DisableZBuffer();
	float halfHeight = aWindowSize.y * 0.5f;
	float halfWidth = aWindowSize.x * 0.5f;
	CU::Vector2<float> steeringPos(halfWidth + mySteeringTargetPosition.x
		, -halfHeight - mySteeringTargetPosition.y);

	if (myConversation.size() > 1)
	{
		myBackgroundConversation->Render({ 15.f, -halfHeight * 1.2f + 20.f + 128.f - 150.f });
	}

	myBackgroundMission->Render({ 15.f, -10.f });

	CU::Vector2<float> crosshairPosition(CU::Math::Lerp<CU::Vector2<float>>({ halfWidth, -halfHeight }
	, { steeringPos.x, steeringPos.y }, 0.3f));

	myReticle->Render({ halfWidth, -halfHeight });
	mySteeringTarget->Render({ steeringPos.x, steeringPos.y });
	myCrosshair->Render(crosshairPosition);

	myFirstSpawn = myWaypointSpawn;
	myFirstSpawnTimer = myWaypointSpawnTimer;

	if (myIsActiveState == true)
	{
		Prism::Engine::GetInstance()->PrintText(myConversation, { 35.f, -halfHeight * 1.2f + 20.f + 128.f - 200.f }, Prism::eTextType::RELEASE_TEXT);
		CalculateAndRender(myWaypointPosition, myModel2DToRender, myWaypointArrow, myWaypointMarker
			, aWindowSize, myWaypointActive);

		for (int i = 0; i < myEnemies.Size(); ++i)
		{
			myFirstSpawn = myEnemies[i]->GetGUIStartReneringMarker();
			myFirstSpawnTimer = myEnemies[i]->GetGUIStartRenderingMarkerTimer();
			if (myFirstSpawn == false && myFirstSpawnTimer != 0) myEnemies[i]->ActivateGUIStartRenderingMarker();
			float lengthToEnemy = CU::Length(myEnemies[i]->myOrientation.GetPos() - myCamera->GetOrientation().GetPos());
			if (lengthToEnemy < my3DClosestEnemyLength)
			{
				my3DClosestEnemyLength = lengthToEnemy;
			}

			if (myEnemies[i]->GetType() == eEntityType::STRUCTURE)
			{
				CalculateAndRender(myEnemies[i]->myOrientation.GetPos(), myModel2DToRender, myStructureArrow
					, myStructureMarker, aWindowSize, true, 1.f, false, "", myEnemies[i]);
			}
			else
			{
				if (lengthToEnemy < myMaxDistanceToEnemies)
				{
					CalculateAndRender(myEnemies[i]->myOrientation.GetPos(), myModel2DToRender, myEnemyArrow, myEnemyMarker, aWindowSize, true);
				}
			}
			CU::Vector2<float> enemyScreenPos = myClosestScreenPos;
			float lengthFromMouseToEnemy = CU::Length(enemyScreenPos - CU::Vector2<float>(steeringPos.x, steeringPos.y));
			if (lengthFromMouseToEnemy < myClosestEnemyLength)
			{
				myClosestEnemy = myEnemies[i];
				myClosestEnemyLength = lengthFromMouseToEnemy;
			}
		}

		if (myEnemies.Size() > 0 && my3DClosestEnemyLength < 1000)
		{
			if (myBattlePlayed == false)
			{
				Prism::Audio::AudioInterface::GetInstance()->PostEvent("Pause_BackgroundMusic", 0);
				Prism::Audio::AudioInterface::GetInstance()->PostEvent("Resume_BattleMusic", 0);

			}
			myBackgroundMusicPlayed = false;
			myBattlePlayed = true;
		}
		else
		{
			if (myBackgroundMusicPlayed == false)
			{
				Prism::Audio::AudioInterface::GetInstance()->PostEvent("Resume_BackgroundMusic", 0);
				Prism::Audio::AudioInterface::GetInstance()->PostEvent("Pause_BattleMusic", 0);
			}
			myBattlePlayed = false;
			myBackgroundMusicPlayed = true;
		}

		for (int i = 0; i < myPowerUps.Size(); ++i)
		{
			myFirstSpawn = myPowerUps[i]->GetGUIStartReneringMarker();
			myFirstSpawnTimer = myPowerUps[i]->GetGUIStartRenderingMarkerTimer();
			if (myFirstSpawn == false && myFirstSpawnTimer != 0) myPowerUps[i]->ActivateGUIStartRenderingMarker();
			CalculateAndRender(myPowerUps[i]->myOrientation.GetPos(), myModel2DToRender, myPowerUpArrow, myPowerUpMarker
				, aWindowSize, true, true, 1.f, myPowerUps[i]->GetComponent<PowerUpComponent>()->GetInGameName());
		}

		if (myEnemiesTarget != nullptr)
		{
			CalculateAndRender(myEnemiesTarget->myOrientation.GetPos(), myModel2DToRender, myDefendArrow, myDefendMarker, aWindowSize, true);
		}

		float percentageToReady = 1.f;

		if (myHasRocketLauncher == true)
		{
			Prism::Engine::GetInstance()->PrintText("RL", { halfWidth + 550.f, -halfHeight + 15.f }, Prism::eTextType::RELEASE_TEXT);

			percentageToReady = *myRocketCurrentTime / *myRocketMaxTime;
			if (percentageToReady >= 1.f)
			{
				if (myPlayedMissilesReady == false)
				{
					myEntity.SendNote<SoundNote>(SoundNote(eSoundNoteType::PLAY, "Play_MissilesReady"));
					myPlayedMissilesReady = true;
				}
				Prism::Engine::GetInstance()->PrintText("RDY", { halfWidth + 550.f, -halfHeight - 20.f }, Prism::eTextType::RELEASE_TEXT);
			}
			else
			{
				myPlayedMissilesReady = false;
			}
		}



		if (myHasHomingWeapon == true)
		{
			if (myClosestEnemy != nullptr)
			{
				myHomingTarget->Rotate(myDeltaTime);
				CalculateAndRender(myClosestEnemy->myOrientation.GetPos(), nullptr, nullptr, nullptr, aWindowSize, true, 1.f);
			}
			myEntity.GetComponent<ShootingComponent>()->SetHomingTarget(myClosestEnemy);
		}
		if (myHasRocketLauncher == true && percentageToReady >= 1.f)
		{
			if (myClosestEnemy != nullptr)
			{
				myHomingTarget->Rotate(myDeltaTime);
				if (myClosestEnemy->GetName() != "E_enemy_turret_noShoot")
				{
					CalculateAndRender(myClosestEnemy->myOrientation.GetPos(), myModel2DToRender, myHomingTarget, myHomingTarget, aWindowSize, true, percentageToReady);
				}
			}

			myEntity.GetComponent<ShootingComponent>()->SetHomingTarget(myClosestEnemy);
		}
	}

	myEnemies.RemoveAll();
	myPowerUps.RemoveAll();

	myGUIBars[0]->Render(*myCamera);

	if (myCurrentShield <= 101.f)
	{
		myGUIBars[1]->Render(*myCamera);
	}
	else
	{
		myGUIBars[2]->Render(*myCamera);
	}

	if (myHitMarkerTimer >= 0.f)
	{
		myCurrentHitmarker->Render(crosshairPosition);
	}

	if (myDamageIndicatorTimer >= 0.f)
	{
		float alpha = fminf(1.f, myDamageIndicatorTimer);
		if (myCurrentShield <= 0)
		{
			myDamageIndicatorHealth->Render({ halfWidth, -halfHeight }, { 1.f, 1.f }, { 1.f, 1.f, 1.f, alpha });
		}
		else
		{
			//myDamageIndicatorShield->Render({ halfWidth, -halfHeight }, { 1.f, 1.f }, { 1.f, 1.f, 1.f, alpha });
		}
	}

	if (myIsActiveState == true)
	{
		if (myClosestEnemy != nullptr)
		{
			CalculateAndRender(myClosestEnemy->myOrientation.GetPos(), nullptr, nullptr, nullptr, aWindowSize
				, true, 1.f, false, "", myClosestEnemy);

			if (myShouldRenderHP == true && myClosestEnemy->GetName() != "E_enemy_turret_noShoot")
			{
				float alpha = CU::Length(steeringPos - myClosestScreenPos);
				alpha = 1.f - (alpha / CIRCLERADIUS);
				Prism::Engine::GetInstance()->PrintText("Hp: " + std::to_string(myClosestEnemy->GetComponent<HealthComponent>()->GetHealth())
					, { myClosestScreenPos.x - 30.f, myClosestScreenPos.y + 40.f }, Prism::eTextType::RELEASE_TEXT
					, 0.5f, { 1.f, 1.f, 1.f, alpha });
			}
		}

		myPowerUpSlots[ePowerUpType::EMP]->Render(aWindowSize, myDeltaTime);
		myPowerUpSlots[ePowerUpType::FIRERATEBOOST]->Render(aWindowSize, myDeltaTime);
		myPowerUpSlots[ePowerUpType::HOMING]->Render(aWindowSize, myDeltaTime);
		myPowerUpSlots[ePowerUpType::INVULNERABLITY]->Render(aWindowSize, myDeltaTime);

		if (myShowMessage == true)
		{
			Prism::Engine::GetInstance()->PrintText(myMessage, { halfWidth - 150.f, -halfHeight + 200.f }, Prism::eTextType::RELEASE_TEXT
				, 1.f, { 1.f, 1.f, 1.f, myMessageAlpha });
		}

		if (myShowTutorialMessage == true)
		{
			Prism::Engine::GetInstance()->PrintText(myTutorialMessage, { halfWidth - 270.f, -halfHeight + 220.f }, Prism::eTextType::RELEASE_TEXT
				, 1.f, { 1.f, 1.f, 1.f, myMessageAlpha });
		}

		if (myHasMachinegun == true)
		{
			Prism::Engine::GetInstance()->PrintText("MG", { halfWidth + 420.f, -halfHeight + 15.f }, Prism::eTextType::RELEASE_TEXT);

			if (*myCurrentWeapon == 0)
			{
				Prism::Engine::GetInstance()->PrintText("RDY", { halfWidth + 420.f, -halfHeight - 20.f }, Prism::eTextType::RELEASE_TEXT);
			}
		}

		if (myHasShotgun == true)
		{
			Prism::Engine::GetInstance()->PrintText("SG", { halfWidth + 480.f, -halfHeight + 15.f }, Prism::eTextType::RELEASE_TEXT);

			if (*myCurrentWeapon == 1)
			{
				Prism::Engine::GetInstance()->PrintText("RDY", { halfWidth + 480.f, -halfHeight - 20.f }, Prism::eTextType::RELEASE_TEXT);
			}
		}

		float speed = myEntity.GetComponent<PhysicsComponent>()->GetSpeed();
		speed += 0.5f;
		int displaySpeed = int(speed);
		if (speed > 99.5f && speed < 102.f)
		{
			displaySpeed = 100;
		}
		if (speed > 250.f)
		{
			displaySpeed = 250;
		}

		Prism::Engine::GetInstance()->PrintText(displaySpeed
			, { halfWidth - 360.f, -halfHeight - 270.f }, Prism::eTextType::RELEASE_TEXT);

		if (myHasEMP == true)
		{
			Prism::Engine::GetInstance()->PrintText("EMP ready. Press [Space] to release."
				, { halfWidth - 240.f, -halfHeight - 270.f }, Prism::eTextType::RELEASE_TEXT, 1.f, { 1.f, 1.f, 1.f, myEMPMessageAlpha });
		}
	}

	Prism::Engine::GetInstance()->EnableZBuffer();
}
Пример #4
0
static int dt_group_get_mask_roi(dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece,
                                 dt_masks_form_t *form, const dt_iop_roi_t *roi, float *buffer)
{
  double start2 = dt_get_wtime();
  const guint nb = g_list_length(form->points);
  if(nb == 0) return 0;
  int nb_ok = 0;

  const int width = roi->width;
  const int height = roi->height;

  // we need to allocate a temporary buffer for intermediate creation of individual shapes
  float *bufs = dt_alloc_align(64, (size_t)width * height * sizeof(float));
  if(bufs == NULL) return 0;

  // empty the output buffer
  memset(buffer, 0, (size_t)width * height * sizeof(float));

  // and we get all masks
  GList *fpts = g_list_first(form->points);

  while(fpts)
  {
    dt_masks_point_group_t *fpt = (dt_masks_point_group_t *)fpts->data;
    dt_masks_form_t *sel = dt_masks_get_from_id(module->dev, fpt->formid);

    if(sel)
    {
      const int ok = dt_masks_get_mask_roi(module, piece, sel, roi, bufs);
      const float op = fpt->opacity;
      const int state = fpt->state;

      if(ok)
      {
        // first see if we need to invert this shape
        if(state & DT_MASKS_STATE_INVERSE)
        {
#ifdef _OPENMP
#if !defined(__SUNOS__) && !defined(__NetBSD__)
#pragma omp parallel for default(none) shared(bufs)
#else
#pragma omp parallel for shared(bufs)
#endif
#endif
          for(int y = 0; y < height; y++)
            for(int x = 0; x < width; x++)
            {
              size_t index = (size_t)y * width + x;
              bufs[index] = 1.0f - bufs[index];
            }
        }

        if(state & DT_MASKS_STATE_UNION)
        {
#ifdef _OPENMP
#if !defined(__SUNOS__) && !defined(__NetBSD__)
#pragma omp parallel for default(none) shared(bufs, buffer)
#else
#pragma omp parallel for shared(bufs, buffer)
#endif
#endif
          for(int y = 0; y < height; y++)
            for(int x = 0; x < width; x++)
            {
              size_t index = (size_t)y * width + x;
              buffer[index] = fmaxf(buffer[index], bufs[index] * op);
            }
        }
        else if(state & DT_MASKS_STATE_INTERSECTION)
        {
#ifdef _OPENMP
#if !defined(__SUNOS__) && !defined(__NetBSD__)
#pragma omp parallel for default(none) shared(bufs, buffer)
#else
#pragma omp parallel for shared(bufs, buffer)
#endif
#endif
          for(int y = 0; y < height; y++)
            for(int x = 0; x < width; x++)
            {
              size_t index = (size_t)y * width + x;
              float b1 = buffer[index];
              float b2 = b2 = bufs[index]; // FIXME: is this line correct? what it supposed to be doing?
              if(b1 > 0.0f && b2 > 0.0f)
                buffer[index] = fminf(b1, b2 * op);
              else
                buffer[index] = 0.0f;
            }
        }
        else if(state & DT_MASKS_STATE_DIFFERENCE)
        {
#ifdef _OPENMP
#if !defined(__SUNOS__) && !defined(__NetBSD__)
#pragma omp parallel for default(none) shared(bufs, buffer)
#else
#pragma omp parallel for shared(bufs, buffer)
#endif
#endif
          for(int y = 0; y < height; y++)
            for(int x = 0; x < width; x++)
            {
              size_t index = (size_t)y * width + x;
              float b1 = buffer[index];
              float b2 = bufs[index] * op;
              if(b1 > 0.0f && b2 > 0.0f) buffer[index] = b1 * (1.0f - b2);
            }
        }
        else if(state & DT_MASKS_STATE_EXCLUSION)
        {
#ifdef _OPENMP
#if !defined(__SUNOS__) && !defined(__NetBSD__)
#pragma omp parallel for default(none) shared(bufs, buffer)
#else
#pragma omp parallel for shared(bufs, buffer)
#endif
#endif
          for(int y = 0; y < height; y++)
            for(int x = 0; x < width; x++)
            {
              size_t index = (size_t)y * width + x;
              float b1 = buffer[index];
              float b2 = bufs[index] * op;
              if(b1 > 0.0f && b2 > 0.0f)
                buffer[index] = fmaxf((1.0f - b1) * b2, b1 * (1.0f - b2));
              else
                buffer[index] = fmaxf(b1, b2);
            }
        }
        else // if we are here, this mean that we just have to copy the shape and null other parts
        {
#ifdef _OPENMP
#if !defined(__SUNOS__) && !defined(__NetBSD__)
#pragma omp parallel for default(none) shared(bufs, buffer)
#else
#pragma omp parallel for shared(bufs, buffer)
#endif
#endif
          for(int y = 0; y < height; y++)
            for(int x = 0; x < width; x++)
            {
              size_t index = (size_t)y * width + x;
              buffer[index] = bufs[index] * op;
            }
        }

        if(darktable.unmuted & DT_DEBUG_PERF)
          dt_print(DT_DEBUG_MASKS, "[masks %d] combine took %0.04f sec\n", nb_ok, dt_get_wtime() - start2);
        start2 = dt_get_wtime();

        nb_ok++;
      }
    }
    fpts = g_list_next(fpts);
  }

  // and we free the intermediate buffer
  dt_free_align(bufs);

  return (nb_ok != 0);
}
Пример #5
0
 /// value of the min coordinate
 float get_min() const {
     return fminf(fminf(x,y),z);
 }
Пример #6
0
unsigned
MultirotorMixer::mix(float *outputs, unsigned space, uint16_t *status_reg)
{
	/* Summary of mixing strategy:
	1) mix roll, pitch and thrust without yaw.
	2) if some outputs violate range [0,1] then try to shift all outputs to minimize violation ->
		increase or decrease total thrust (boost). The total increase or decrease of thrust is limited
		(max_thrust_diff). If after the shift some outputs still violate the bounds then scale roll & pitch.
		In case there is violation at the lower and upper bound then try to shift such that violation is equal
		on both sides.
	3) mix in yaw and scale if it leads to limit violation.
	4) scale all outputs to range [idle_speed,1]
	*/

	float		roll    = constrain(get_control(0, 0) * _roll_scale, -1.0f, 1.0f);
	float		pitch   = constrain(get_control(0, 1) * _pitch_scale, -1.0f, 1.0f);
	float		yaw     = constrain(get_control(0, 2) * _yaw_scale, -1.0f, 1.0f);
	float		thrust  = constrain(get_control(0, 3), 0.0f, 1.0f);
	float		min_out = 1.0f;
	float		max_out = 0.0f;

	// clean out class variable used to capture saturation
	_saturation_status.value = 0;

	// thrust boost parameters
	float thrust_increase_factor = 1.5f;
	float thrust_decrease_factor = 0.6f;

	/* perform initial mix pass yielding unbounded outputs, ignore yaw */
	for (unsigned i = 0; i < _rotor_count; i++) {
		float out = roll * _rotors[i].roll_scale +
			    pitch * _rotors[i].pitch_scale +
			    thrust;

		out *= _rotors[i].out_scale;

		/* calculate min and max output values */
		if (out < min_out) {
			min_out = out;
		}

		if (out > max_out) {
			max_out = out;
		}

		outputs[i] = out;
	}

	float boost = 0.0f;		// value added to demanded thrust (can also be negative)
	float roll_pitch_scale = 1.0f;	// scale for demanded roll and pitch

	if (min_out < 0.0f && max_out < 1.0f && -min_out <= 1.0f - max_out) {
		float max_thrust_diff = thrust * thrust_increase_factor - thrust;

		if (max_thrust_diff >= -min_out) {
			boost = -min_out;

		} else {
			boost = max_thrust_diff;
			roll_pitch_scale = (thrust + boost) / (thrust - min_out);
		}

	} else if (max_out > 1.0f && min_out > 0.0f && min_out >= max_out - 1.0f) {
		float max_thrust_diff = thrust - thrust_decrease_factor * thrust;

		if (max_thrust_diff >= max_out - 1.0f) {
			boost = -(max_out - 1.0f);

		} else {
			boost = -max_thrust_diff;
			roll_pitch_scale = (1 - (thrust + boost)) / (max_out - thrust);
		}

	} else if (min_out < 0.0f && max_out < 1.0f && -min_out > 1.0f - max_out) {
		float max_thrust_diff = thrust * thrust_increase_factor - thrust;
		boost = constrain(-min_out - (1.0f - max_out) / 2.0f, 0.0f, max_thrust_diff);
		roll_pitch_scale = (thrust + boost) / (thrust - min_out);

	} else if (max_out > 1.0f && min_out > 0.0f && min_out < max_out - 1.0f) {
		float max_thrust_diff = thrust - thrust_decrease_factor * thrust;
		boost = constrain(-(max_out - 1.0f - min_out) / 2.0f, -max_thrust_diff, 0.0f);
		roll_pitch_scale = (1 - (thrust + boost)) / (max_out - thrust);

	} else if (min_out < 0.0f && max_out > 1.0f) {
		boost = constrain(-(max_out - 1.0f + min_out) / 2.0f, thrust_decrease_factor * thrust - thrust,
				  thrust_increase_factor * thrust - thrust);
		roll_pitch_scale = (thrust + boost) / (thrust - min_out);
	}

	// capture saturation
	if (min_out < 0.0f) {
		_saturation_status.flags.motor_neg = true;
	}

	if (max_out > 1.0f) {
		_saturation_status.flags.motor_pos = true;
	}

	// mix again but now with thrust boost, scale roll/pitch and also add yaw
	for (unsigned i = 0; i < _rotor_count; i++) {
		float out = (roll * _rotors[i].roll_scale +
			     pitch * _rotors[i].pitch_scale) * roll_pitch_scale +
			    yaw * _rotors[i].yaw_scale +
			    thrust + boost;

		out *= _rotors[i].out_scale;

		// scale yaw if it violates limits. inform about yaw limit reached
		if (out < 0.0f) {
			if (fabsf(_rotors[i].yaw_scale) <= FLT_EPSILON) {
				yaw = 0.0f;

			} else {
				yaw = -((roll * _rotors[i].roll_scale + pitch * _rotors[i].pitch_scale) *
					roll_pitch_scale + thrust + boost) / _rotors[i].yaw_scale;
			}

		} else if (out > 1.0f) {
			// allow to reduce thrust to get some yaw response
			float thrust_reduction = fminf(0.15f, out - 1.0f);
			thrust -= thrust_reduction;

			if (fabsf(_rotors[i].yaw_scale) <= FLT_EPSILON) {
				yaw = 0.0f;

			} else {
				yaw = (1.0f - ((roll * _rotors[i].roll_scale + pitch * _rotors[i].pitch_scale) *
					       roll_pitch_scale + thrust + boost)) / _rotors[i].yaw_scale;
			}
		}
	}

	/* add yaw and scale outputs to range idle_speed...1 */
	for (unsigned i = 0; i < _rotor_count; i++) {
		outputs[i] = (roll * _rotors[i].roll_scale +
			      pitch * _rotors[i].pitch_scale) * roll_pitch_scale +
			     yaw * _rotors[i].yaw_scale +
			     thrust + boost;

		/*
			implement simple model for static relationship between applied motor pwm and motor thrust
			model: thrust = (1 - _thrust_factor) * PWM + _thrust_factor * PWM^2
			this model assumes normalized input / output in the range [0,1] so this is the right place
			to do it as at this stage the outputs are in that range.
		 */
		if (_thrust_factor > 0.0f) {
			outputs[i] = -(1.0f - _thrust_factor) / (2.0f * _thrust_factor) + sqrtf((1.0f - _thrust_factor) *
					(1.0f - _thrust_factor) / (4.0f * _thrust_factor * _thrust_factor) + (outputs[i] < 0.0f ? 0.0f : outputs[i] /
							_thrust_factor));
		}

		outputs[i] = constrain(_idle_speed + (outputs[i] * (1.0f - _idle_speed)), _idle_speed, 1.0f);

	}

	/* slew rate limiting and saturation checking */
	for (unsigned i = 0; i < _rotor_count; i++) {
		bool clipping_high = false;
		bool clipping_low = false;

		// check for saturation against static limits
		if (outputs[i] > 0.99f) {
			clipping_high = true;

		} else if (outputs[i] < _idle_speed + 0.01f) {
			clipping_low = true;

		}

		// check for saturation against slew rate limits
		if (_delta_out_max > 0.0f) {
			float delta_out = outputs[i] - _outputs_prev[i];

			if (delta_out > _delta_out_max) {
				outputs[i] = _outputs_prev[i] + _delta_out_max;
				clipping_high = true;

			} else if (delta_out < -_delta_out_max) {
				outputs[i] = _outputs_prev[i] - _delta_out_max;
				clipping_low = true;

			}
		}

		_outputs_prev[i] = outputs[i];

		// update the saturation status report
		update_saturation_status(i, clipping_high, clipping_low);

	}

	// this will force the caller of the mixer to always supply new slew rate values, otherwise no slew rate limiting will happen
	_delta_out_max = 0.0f;

	// Notify saturation status
	if (status_reg != NULL) {
		(*status_reg) = _saturation_status.value;
	}

	return _rotor_count;
}
Пример #7
0
void modify_roi_in(struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *roi_out, dt_iop_roi_t *roi_in)
{
    *roi_in = *roi_out;

    int roir = roi_in->width+roi_in->x;
    int roib = roi_in->height+roi_in->y;
    int roix = roi_in->x;
    int roiy = roi_in->y;

    //dt_iop_spots_params_t *d = (dt_iop_spots_params_t *)piece->data;
    dt_develop_blend_params_t *bp = self->blend_params;

    // We iterate through all spots or polygons
    dt_masks_form_t *grp = dt_masks_get_from_id(darktable.develop,bp->mask_id);
    if (grp && (grp->type & DT_MASKS_GROUP))
    {
        GList *forms = g_list_first(grp->points);
        while(forms)
        {
            dt_masks_point_group_t *grpt = (dt_masks_point_group_t *)forms->data;
            //we get the spot
            dt_masks_form_t *form = dt_masks_get_from_id(self->dev,grpt->formid);
            if (form)
            {
                //we get the area for the form
                int fl,ft,fw,fh;
                if (!dt_masks_get_area(self,piece,form,&fw,&fh,&fl,&ft))
                {
                    forms = g_list_next(forms);
                    continue;
                }

                //if the form is outside the roi, we just skip it
                fw *= roi_in->scale, fh *= roi_in->scale, fl *= roi_in->scale, ft *= roi_in->scale;
                if (ft>=roi_out->y+roi_out->height || ft+fh<=roi_out->y || fl>=roi_out->x+roi_out->width || fl+fw<=roi_out->x)
                {
                    forms = g_list_next(forms);
                    continue;
                }

                //we get the area for the source
                if (!dt_masks_get_source_area(self,piece,form,&fw,&fh,&fl,&ft))
                {
                    forms = g_list_next(forms);
                    continue;
                }
                fw *= roi_in->scale, fh *= roi_in->scale, fl *= roi_in->scale, ft *= roi_in->scale;

                //we enlarge the roi if needed
                roiy = fminf(ft,roiy);
                roix = fminf(fl,roix);
                roir = fmaxf(fl+fw,roir);
                roib = fmaxf(ft+fh,roib);
            }
            forms = g_list_next(forms);
        }
    }

    //now we set the values
    roi_in->x = CLAMP(roix, 0, piece->pipe->iwidth*roi_in->scale-1);
    roi_in->y = CLAMP(roiy, 0, piece->pipe->iheight*roi_in->scale-1);
    roi_in->width = CLAMP(roir-roi_in->x, 1, piece->pipe->iwidth*roi_in->scale-roi_in->x);
    roi_in->height = CLAMP(roib-roi_in->y, 1, piece->pipe->iheight*roi_in->scale-roi_in->y);
}
Пример #8
0
void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
             void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
{
  const uint32_t filters = piece->pipe->dsc.filters;
  dt_iop_highlights_data_t *data = (dt_iop_highlights_data_t *)piece->data;

  const float clip
      = data->clip * fminf(piece->pipe->dsc.processed_maximum[0],
                           fminf(piece->pipe->dsc.processed_maximum[1], piece->pipe->dsc.processed_maximum[2]));
  // const int ch = piece->colors;
  if(!filters)
  {
    process_clip(piece, ivoid, ovoid, roi_in, roi_out, clip);
    for(int k=0;k<3;k++)
      piece->pipe->dsc.processed_maximum[k]
          = fminf(piece->pipe->dsc.processed_maximum[0],
                  fminf(piece->pipe->dsc.processed_maximum[1], piece->pipe->dsc.processed_maximum[2]));
    return;
  }

  switch(data->mode)
  {
    case DT_IOP_HIGHLIGHTS_INPAINT: // a1ex's (magiclantern) idea of color inpainting:
    {
      const float clips[4] = { 0.987 * data->clip * piece->pipe->dsc.processed_maximum[0],
                               0.987 * data->clip * piece->pipe->dsc.processed_maximum[1],
                               0.987 * data->clip * piece->pipe->dsc.processed_maximum[2], clip };

      if(filters == 9u)
      {
        const uint8_t(*const xtrans)[6] = (const uint8_t(*const)[6])piece->pipe->dsc.xtrans;
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic) default(none)
#endif
        for(int j = 0; j < roi_out->height; j++)
        {
          interpolate_color_xtrans(ivoid, ovoid, roi_in, roi_out, 0, 1, j, clips, xtrans, 0);
          interpolate_color_xtrans(ivoid, ovoid, roi_in, roi_out, 0, -1, j, clips, xtrans, 1);
        }
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic) default(none)
#endif
        for(int i = 0; i < roi_out->width; i++)
        {
          interpolate_color_xtrans(ivoid, ovoid, roi_in, roi_out, 1, 1, i, clips, xtrans, 2);
          interpolate_color_xtrans(ivoid, ovoid, roi_in, roi_out, 1, -1, i, clips, xtrans, 3);
        }
      }
      else
      {
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic) default(none) shared(data, piece)
#endif
        for(int j = 0; j < roi_out->height; j++)
        {
          interpolate_color(ivoid, ovoid, roi_out, 0, 1, j, clips, filters, 0);
          interpolate_color(ivoid, ovoid, roi_out, 0, -1, j, clips, filters, 1);
        }

// up/down directions
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic) default(none) shared(data, piece)
#endif
        for(int i = 0; i < roi_out->width; i++)
        {
          interpolate_color(ivoid, ovoid, roi_out, 1, 1, i, clips, filters, 2);
          interpolate_color(ivoid, ovoid, roi_out, 1, -1, i, clips, filters, 3);
        }
      }
      break;
    }
    case DT_IOP_HIGHLIGHTS_LCH:
      if(filters == 9u)
        process_lch_xtrans(self, piece, ivoid, ovoid, roi_in, roi_out, clip);
      else
        process_lch_bayer(self, piece, ivoid, ovoid, roi_in, roi_out, clip);
      break;
    default:
    case DT_IOP_HIGHLIGHTS_CLIP:
      process_clip(piece, ivoid, ovoid, roi_in, roi_out, clip);
      break;
  }

  // update processed maximum
  const float m = fmaxf(fmaxf(piece->pipe->dsc.processed_maximum[0], piece->pipe->dsc.processed_maximum[1]),
                        piece->pipe->dsc.processed_maximum[2]);
  for(int k = 0; k < 3; k++) piece->pipe->dsc.processed_maximum[k] = m;

  if(piece->pipe->mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK) dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
}
Пример #9
0
static gboolean dt_iop_levels_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
{
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  dt_iop_levels_gui_data_t *c = (dt_iop_levels_gui_data_t *)self->gui_data;
  dt_iop_levels_params_t *p = (dt_iop_levels_params_t *)self->params;
  const int inset = DT_GUI_CURVE_EDITOR_INSET;
  int height = widget->allocation.height - 2*inset, width = widget->allocation.width - 2*inset;
  if(!c->dragging)
  {
    c->mouse_x = CLAMP(event->x - inset, 0, width);
    c->drag_start_percentage = (p->levels[1] - p->levels[0])
                               / (p->levels[2] - p->levels[0]);
  }
  c->mouse_y = CLAMP(event->y - inset, 0, height);

  if(c->dragging)
  {
    if(c->handle_move >= 0 && c->handle_move < 3)
    {
      const float mx = (CLAMP(event->x - inset, 0, width)) / (float)width;

      float min_x = 0;
      float max_x = 1;

      // Determining the minimum and maximum bounds for the drag handles
      switch(c->handle_move)
      {
      case 0:
        max_x = fminf(p->levels[2] - (0.05 / c->drag_start_percentage),
                      1);
        max_x = fminf((p->levels[2] * (1 - c->drag_start_percentage) - 0.05)
                      / (1 - c->drag_start_percentage),
                      max_x);
        break;

      case 1:
        min_x = p->levels[0] + 0.05;
        max_x = p->levels[2] - 0.05;
        break;

      case 2:
        min_x = fmaxf((0.05 / c->drag_start_percentage) + p->levels[0],
                      0);
        min_x = fmaxf((p->levels[0] * (1 - c->drag_start_percentage) + 0.05)
                      / (1 - c->drag_start_percentage),
                      min_x);
        break;
      }

      p->levels[c->handle_move] =
          fminf(max_x, fmaxf(min_x, mx));

      if(c->handle_move != 1)
        p->levels[1] = p->levels[0] + (c->drag_start_percentage
                                       * (p->levels[2] - p->levels[0]));
    }
    dt_dev_add_history_item(darktable.develop, self, TRUE);
  }
  else
  {
    c->handle_move = 0;
    const float mx = CLAMP(event->x - inset, 0, width)/(float)width;
    float dist = fabsf(p->levels[0] - mx);
    for(int k=1; k<3; k++)
    {
      float d2 = fabsf(p->levels[k] - mx);
      if(d2 < dist)
      {
        c->handle_move = k;
        dist = d2;
      }
    }
  }
  gtk_widget_queue_draw(widget);

  gint x, y;
  gdk_window_get_pointer(event->window, &x, &y, NULL);
  return TRUE;
}
Пример #10
0
int process_cl(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out,
               const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
{
  dt_iop_highlights_data_t *d = (dt_iop_highlights_data_t *)piece->data;
  dt_iop_highlights_global_data_t *gd = (dt_iop_highlights_global_data_t *)self->data;

  cl_int err = -999;
  cl_mem dev_xtrans = NULL;

  const int devid = piece->pipe->devid;
  const int width = roi_in->width;
  const int height = roi_in->height;

  const float clip = d->clip
                     * fminf(piece->pipe->dsc.processed_maximum[0],
                             fminf(piece->pipe->dsc.processed_maximum[1], piece->pipe->dsc.processed_maximum[2]));

  const uint32_t filters = piece->pipe->dsc.filters;

  if(!filters)
  {
    // non-raw images use dedicated kernel which just clips
    size_t sizes[] = { ROUNDUPWD(width), ROUNDUPHT(height), 1 };
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_4f_clip, 0, sizeof(cl_mem), (void *)&dev_in);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_4f_clip, 1, sizeof(cl_mem), (void *)&dev_out);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_4f_clip, 2, sizeof(int), (void *)&width);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_4f_clip, 3, sizeof(int), (void *)&height);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_4f_clip, 4, sizeof(int), (void *)&d->mode);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_4f_clip, 5, sizeof(float), (void *)&clip);
    err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_highlights_4f_clip, sizes);
    if(err != CL_SUCCESS) goto error;
  }
  else if(d->mode == DT_IOP_HIGHLIGHTS_CLIP)
  {
    // raw images with clip mode (both bayer and xtrans)
    size_t sizes[] = { ROUNDUPWD(width), ROUNDUPHT(height), 1 };
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_clip, 0, sizeof(cl_mem), (void *)&dev_in);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_clip, 1, sizeof(cl_mem), (void *)&dev_out);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_clip, 2, sizeof(int), (void *)&width);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_clip, 3, sizeof(int), (void *)&height);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_clip, 4, sizeof(float), (void *)&clip);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_clip, 5, sizeof(int), (void *)&roi_out->x);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_clip, 6, sizeof(int), (void *)&roi_out->y);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_clip, 7, sizeof(int), (void *)&filters);
    err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_highlights_1f_clip, sizes);
    if(err != CL_SUCCESS) goto error;
  }
  else if(d->mode == DT_IOP_HIGHLIGHTS_LCH && filters != 9u)
  {
    // bayer sensor raws with LCH mode
    size_t sizes[] = { ROUNDUPWD(width), ROUNDUPHT(height), 1 };
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_bayer, 0, sizeof(cl_mem), (void *)&dev_in);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_bayer, 1, sizeof(cl_mem), (void *)&dev_out);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_bayer, 2, sizeof(int), (void *)&width);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_bayer, 3, sizeof(int), (void *)&height);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_bayer, 4, sizeof(float), (void *)&clip);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_bayer, 5, sizeof(int), (void *)&roi_out->x);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_bayer, 6, sizeof(int), (void *)&roi_out->y);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_bayer, 7, sizeof(int), (void *)&filters);
    err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_highlights_1f_lch_bayer, sizes);
    if(err != CL_SUCCESS) goto error;
  }
  else if(d->mode == DT_IOP_HIGHLIGHTS_LCH && filters == 9u)
  {
    // xtrans sensor raws with LCH mode
    int blocksizex, blocksizey;

    dt_opencl_local_buffer_t locopt
      = (dt_opencl_local_buffer_t){ .xoffset = 2 * 2, .xfactor = 1, .yoffset = 2 * 2, .yfactor = 1,
                                    .cellsize = sizeof(float), .overhead = 0,
                                    .sizex = 1 << 8, .sizey = 1 << 8 };

    if(dt_opencl_local_buffer_opt(devid, gd->kernel_highlights_1f_lch_xtrans, &locopt))
    {
      blocksizex = locopt.sizex;
      blocksizey = locopt.sizey;
    }
    else
      blocksizex = blocksizey = 1;

    dev_xtrans
        = dt_opencl_copy_host_to_device_constant(devid, sizeof(piece->pipe->dsc.xtrans), piece->pipe->dsc.xtrans);
    if(dev_xtrans == NULL) goto error;

    size_t sizes[] = { ROUNDUP(width, blocksizex), ROUNDUP(height, blocksizey), 1 };
    size_t local[] = { blocksizex, blocksizey, 1 };
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_xtrans, 0, sizeof(cl_mem), (void *)&dev_in);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_xtrans, 1, sizeof(cl_mem), (void *)&dev_out);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_xtrans, 2, sizeof(int), (void *)&width);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_xtrans, 3, sizeof(int), (void *)&height);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_xtrans, 4, sizeof(float), (void *)&clip);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_xtrans, 5, sizeof(int), (void *)&roi_out->x);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_xtrans, 6, sizeof(int), (void *)&roi_out->y);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_xtrans, 7, sizeof(cl_mem), (void *)&dev_xtrans);
    dt_opencl_set_kernel_arg(devid, gd->kernel_highlights_1f_lch_xtrans, 8,
                               (blocksizex + 4) * (blocksizey + 4) * sizeof(float), NULL);

    err = dt_opencl_enqueue_kernel_2d_with_local(devid, gd->kernel_highlights_1f_lch_xtrans, sizes, local);
    if(err != CL_SUCCESS) goto error;
  }

  // update processed maximum
  const float m = fmaxf(fmaxf(piece->pipe->dsc.processed_maximum[0], piece->pipe->dsc.processed_maximum[1]),
                        piece->pipe->dsc.processed_maximum[2]);
  for(int k = 0; k < 3; k++) piece->pipe->dsc.processed_maximum[k] = m;

  dt_opencl_release_mem_object(dev_xtrans);
  return TRUE;

error:
  dt_opencl_release_mem_object(dev_xtrans);
  dt_print(DT_DEBUG_OPENCL, "[opencl_highlights] couldn't enqueue kernel! %d\n", err);
  return FALSE;
}
Пример #11
0
static inline void interpolate_color_xtrans(const void *const ivoid, void *const ovoid,
                                            const dt_iop_roi_t *const roi_in,
                                            const dt_iop_roi_t *const roi_out,
                                            int dim, int dir, int other,
                                            const float *const clip,
                                            const uint8_t (*const xtrans)[6],
                                            const int pass)
{
  // In Bayer each row/col has only green/red or green/blue
  // transitions, hence can reconstruct color by single ratio per
  // row. In x-trans there can be transitions between arbitrary colors
  // in a row/col (and 2x2 green blocks which provide no color
  // transition information). Hence calculate multiple color ratios
  // for each row/col.

  // Lookup for color ratios, e.g. red -> blue is roff[0][2] and blue
  // -> red is roff[2][0]. Returned value is an index into ratios. If
  // negative, then need to invert the ratio. Identity color
  // transitions aren't used.
  const int roff[3][3] = {{ 0, -1, -2},
                          { 1,  0, -3},
                          { 2,  3,  0}};
  // record ratios of color transitions 0:unused, 1:RG, 2:RB, and 3:GB
  float ratios[4] = {1.0f, 1.0f, 1.0f, 1.0f};

  // passes are 0:+x, 1:-x, 2:+y, 3:-y
  // dims are 0:traverse a row, 1:traverse a column
  // dir is 1:left to right, -1: right to left
  int i = (dim == 0) ? 0 : other;
  int j = (dim == 0) ? other : 0;
  const ssize_t offs = (dim ? roi_out->width : 1) * ((dir < 0) ? -1 : 1);
  const ssize_t offl = offs - (dim ? 1 : roi_out->width);
  const ssize_t offr = offs + (dim ? 1 : roi_out->width);
  int beg, end;
  if(dir == 1)
  {
    beg = 0;
    end = (dim == 0) ? roi_out->width : roi_out->height;
  }
  else
  {
    beg = ((dim == 0) ? roi_out->width : roi_out->height) - 1;
    end = -1;
  }

  float *in, *out;
  if(dim == 1)
  {
    out = (float *)ovoid + (size_t)i + (size_t)beg * roi_out->width;
    in = (float *)ivoid + (size_t)i + (size_t)beg * roi_in->width;
  }
  else
  {
    out = (float *)ovoid + (size_t)beg + (size_t)j * roi_out->width;
    in = (float *)ivoid + (size_t)beg + (size_t)j * roi_in->width;
  }

  for(int k = beg; k != end; k += dir)
  {
    if(dim == 1)
      j = k;
    else
      i = k;

    const uint8_t f0 = FCxtrans(j, i, roi_in, xtrans);
    const uint8_t f1 = FCxtrans(dim ? (j + dir) : j, dim ? i : (i + dir), roi_in, xtrans);
    const uint8_t fl = FCxtrans(dim ? (j + dir) : (j - 1), dim ? (i - 1) : (i + dir), roi_in, xtrans);
    const uint8_t fr = FCxtrans(dim ? (j + dir) : (j + 1), dim ? (i + 1) : (i + dir), roi_in, xtrans);
    const float clip0 = clip[f0];
    const float clip1 = clip[f1];
    const float clipl = clip[fl];
    const float clipr = clip[fr];
    const float clip_max = fmaxf(fmaxf(clip[0], clip[1]), clip[2]);

    if(i == 0 || i == roi_out->width - 1 || j == 0 || j == roi_out->height - 1)
    {
      if(pass == 3) out[0] = fminf(clip_max, in[0]);
    }
    else
    {
      // ratio to next pixel if this & next are unclamped and not in
      // 2x2 green block
      if ((f0 != f1) &&
          (in[0] < clip0 && in[0] > 1e-5f) &&
          (in[offs] < clip1 && in[offs] > 1e-5f))
      {
        const int r = roff[f0][f1];
        assert(r != 0);
        if (r > 0)
          ratios[r] = (3.f * ratios[r] + (in[offs] / in[0])) / 4.f;
        else
          ratios[-r] = (3.f * ratios[-r] + (in[0] / in[offs])) / 4.f;
      }

      if(in[0] >= clip0 - 1e-5f)
      {
        // interplate color for clipped pixel
        float add;
        if(f0 != f1)
          // next pixel is different color
          add =
            interp_pix_xtrans(roff[f0][f1], offs, clip0, clip1, in, ratios);
        else
          // at start of 2x2 green block, look diagonally
          add = (fl != f0) ?
            interp_pix_xtrans(roff[f0][fl], offl, clip0, clipl, in, ratios) :
            interp_pix_xtrans(roff[f0][fr], offr, clip0, clipr, in, ratios);

        if(pass == 0)
          out[0] = add;
        else if(pass == 3)
          out[0] = fminf(clip_max, (out[0] + add) / 4.0f);
        else
          out[0] += add;
      }
      else
      {
        // pixel is not clipped
        if(pass == 3) out[0] = in[0];
      }
    }
    out += offs;
    in += offs;
  }
}
Пример #12
0
void App::update(float delta_time) {
	if (anim_play) frame_count++;

	if (!hide_gui) gui();

	// autoreload frag shader (every 60 frames)
	if (shader_filepath && shader_file_autoreload && (frame_count % 60) == 0) {
		struct stat attr;
		if (!stat(shader_filepath, &attr)) { // file exists
			if (attr.st_mtime > shader_file_mtime) { // file has been modified
				shader_file_mtime = (int)attr.st_mtime;
				reloadShader();
			}
		}
	}

	// update camera (-z: forward, y: up)
	camera_euler_angles += 2.0f*delta_time
		* v3(-movement_command.rotate.x, -movement_command.rotate.y, 0.0f);
	camera_euler_angles.x = fminf(fmaxf(-0.5f*(float)M_PI, camera_euler_angles.x), 0.5f*(float)M_PI); // clamp
	mat3 rot_x = rotationMatrix(v3(1.0f, 0.0f, 0.0f), camera_euler_angles.x);
	mat3 rot_y = rotationMatrix(v3(0.0f, 1.0f, 0.0f), camera_euler_angles.y);
	mat3 rot_z = rotationMatrix(v3(0.0f, 0.0f, 1.0f), camera_euler_angles.z);
	mat3 rot = rot_y * rot_x * rot_z;
	camera_location += rot * (8.0f*delta_time*movement_command.move);
	mat4 view_to_world = translationMatrix(camera_location) * m4(rot);
	mat4 world_to_view = m4(transpose(rot)) * translationMatrix(-camera_location);

	// bind textures
	for (int tsi = 0; tsi < (int)ARRAY_COUNT(texture_slots); tsi++) {
		glActiveTexture(GL_TEXTURE0+tsi);
		glBindTexture(texture_slots[tsi].target, texture_slots[tsi].texture);
	}

	// draw fullscreen triangle(s)
	glClearColor(0.2f, 0.21f, 0.22f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);
	{ BindShader bind_shader(shader);
		if (!compile_error_log) {
			for (int i = 0; i < uniform_count; i++) {
				uniforms[i].apply();
			}
		}

		// apply builtin uniforms
		u_time = (float)frame_count / 60.0f;
		glUniform1f(shader.getUniformLocation(u_time_name), u_time);
		vec2 u_resolution = v2(video.pixel_scale*video.width, video.pixel_scale*video.height);
		glUniform2fv(shader.getUniformLocation(u_resolution_name), 1, u_resolution.e);
		glUniformMatrix4fv(shader.getUniformLocation(u_view_to_world_name), 1, GL_FALSE, view_to_world.e);
		glUniformMatrix4fv(shader.getUniformLocation(u_world_to_view_name), 1, GL_FALSE, world_to_view.e);

		if (single_triangle_mode) {
			{ BindArrayBuffer bind_array_buffer(single_triangle_vbo);
				glEnableVertexAttribArray(VAT_POSITION);
				glVertexAttribPointer(VAT_POSITION, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
				glDrawArrays(GL_TRIANGLES, 0, 3);
				glDisableVertexAttribArray(VAT_POSITION);
			}
		} else {
			{ BindArrayBuffer bind_array_buffer(two_triangles_vbo);
				glEnableVertexAttribArray(VAT_POSITION);
				glVertexAttribPointer(VAT_POSITION, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
				glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
				glDisableVertexAttribArray(VAT_POSITION);
			}
		}
	}
}
Пример #13
0
static gboolean
dt_iop_zonesystem_preview_expose (GtkWidget *widget, GdkEventExpose *event, dt_iop_module_t *self)
{
  const int inset = 2;
  int width = widget->allocation.width, height = widget->allocation.height;

  dt_iop_zonesystem_gui_data_t *g = (dt_iop_zonesystem_gui_data_t *)self->gui_data;
  dt_iop_zonesystem_params_t *p = (dt_iop_zonesystem_params_t *)self->params;

  cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);

  /* clear background */
  GtkStateType state = gtk_widget_get_state(self->expander);
  GtkStyle *style = gtk_widget_get_style(self->expander);
  cairo_set_source_rgb (cr, style->bg[state].red/65535.0, style->bg[state].green/65535.0, style->bg[state].blue/65535.0);
  cairo_paint (cr);

  width -= 2*inset;
  height -= 2*inset;
  cairo_translate(cr, inset, inset);

  dt_pthread_mutex_lock(&g->lock);
  if( g->preview_buffer && self->enabled)
  {
    /* calculate the zonemap */
    float zonemap[MAX_ZONE_SYSTEM_SIZE]= {-1};
    _iop_zonesystem_calculate_zonemap (p,zonemap);

    /* let's generate a pixbuf from pixel zone buffer */
    guchar *image = g_malloc ((g->preview_width*g->preview_height)*4);
    for (int k=0; k<g->preview_width*g->preview_height; k++)
    {
      int zone = 255*CLIP (((1.0/(p->size-1))*g->preview_buffer[k]));
      image[4*k+2] = (g->hilite_zone && g->preview_buffer[k]==g->zone_under_mouse)?255:zone;
      image[4*k+1] = (g->hilite_zone && g->preview_buffer[k]==g->zone_under_mouse)?255:zone;
      image[4*k+0] = (g->hilite_zone && g->preview_buffer[k]==g->zone_under_mouse)?0:zone;
    }
    dt_pthread_mutex_unlock(&g->lock);

    const int wd = g->preview_width, ht = g->preview_height;
    const float scale = fminf(width/(float)wd, height/(float)ht);
    const int stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, wd);
    cairo_surface_t *surface = cairo_image_surface_create_for_data (image, CAIRO_FORMAT_RGB24, wd, ht, stride);
    cairo_translate(cr, width/2.0, height/2.0f);
    cairo_scale(cr, scale, scale);
    cairo_translate(cr, -.5f*wd, -.5f*ht);

    cairo_rectangle(cr, 1, 1, wd-2, ht-2);
    cairo_set_source_surface (cr, surface, 0, 0);
    cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_GOOD);
    cairo_fill_preserve(cr);
    cairo_surface_destroy (surface);

    cairo_set_line_width(cr, 1.0);
    cairo_set_source_rgb(cr, .1, .1, .1);
    cairo_stroke(cr);

    g_free(image);
  }
  else
    dt_pthread_mutex_unlock(&g->lock);

  cairo_destroy(cr);
  cairo_t *cr_pixmap = gdk_cairo_create(gtk_widget_get_window(widget));
  cairo_set_source_surface (cr_pixmap, cst, 0, 0);
  cairo_paint(cr_pixmap);
  cairo_destroy(cr_pixmap);
  cairo_surface_destroy(cst);

  return TRUE;
}
Пример #14
0
// internal function: to avoid exif blob reading + 8-bit byteorder flag + high-quality override
int dt_imageio_export_with_flags(
  const uint32_t              imgid,
  const char                 *filename,
  dt_imageio_module_format_t *format,
  dt_imageio_module_data_t   *format_params,
  const int32_t               ignore_exif,
  const int32_t               display_byteorder,
  const gboolean              high_quality,
  const int32_t               thumbnail_export,
  const char                 *filter,
  const gboolean              copy_metadata,
  dt_imageio_module_storage_t *storage,
  dt_imageio_module_data_t   *storage_params)
{
  dt_develop_t dev;
  dt_dev_init(&dev, 0);
  dt_mipmap_buffer_t buf;
  if(thumbnail_export && dt_conf_get_bool("plugins/lighttable/low_quality_thumbnails"))
    dt_mipmap_cache_read_get(darktable.mipmap_cache, &buf, imgid, DT_MIPMAP_F, DT_MIPMAP_BLOCKING);
  else
    dt_mipmap_cache_read_get(darktable.mipmap_cache, &buf, imgid, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING);
  dt_dev_load_image(&dev, imgid);
  const dt_image_t *img = &dev.image_storage;
  const int wd = img->width;
  const int ht = img->height;

  int res = 0;

  dt_times_t start;
  dt_get_times(&start);
  dt_dev_pixelpipe_t pipe;
  res = thumbnail_export ? dt_dev_pixelpipe_init_thumbnail(&pipe, wd, ht) : dt_dev_pixelpipe_init_export(&pipe, wd, ht, format->levels(format_params));
  if(!res)
  {
    dt_control_log(_("failed to allocate memory for %s, please lower the threads used for export or buy more memory."), thumbnail_export ? C_("noun", "thumbnail export") : C_("noun", "export"));
    dt_dev_cleanup(&dev);
    dt_mipmap_cache_read_release(darktable.mipmap_cache, &buf);
    return 1;
  }

  if(!buf.buf)
  {
    dt_control_log(_("image `%s' is not available!"), img->filename);
    dt_mipmap_cache_read_release(darktable.mipmap_cache, &buf);
    dt_dev_cleanup(&dev);
    return 1;
  }

  //  If a style is to be applied during export, add the iop params into the history
  if (!thumbnail_export && format_params->style[0] != '\0')
  {
    GList *stls;

    GList *modules = dev.iop;
    dt_iop_module_t *m = NULL;

    if ((stls=dt_styles_get_item_list(format_params->style, TRUE, -1)) == 0)
    {
      dt_control_log(_("cannot find the style '%s' to apply during export."), format_params->style);
      dt_dev_cleanup(&dev);
      dt_mipmap_cache_read_release(darktable.mipmap_cache, &buf);
      return 1;
    }

    //  Add each params
    while (stls)
    {
      dt_style_item_t *s = (dt_style_item_t *) stls->data;

      modules = dev.iop;
      while (modules)
      {
        m = (dt_iop_module_t *)modules->data;

        //  since the name in the style is returned with a possible multi-name, just check the start of the name
        if (strncmp(m->op, s->name, strlen(m->op)) == 0)
        {
          dt_dev_history_item_t *h = malloc(sizeof(dt_dev_history_item_t));

          h->params = s->params;
          h->blend_params = s->blendop_params;
          h->enabled = s->enabled;
          h->module = m;
          h->multi_priority = 1;
          g_strlcpy(h->multi_name, "", sizeof(h->multi_name));

          if(m->legacy_params && (s->module_version != m->version()))
          {
            void *new_params = malloc(m->params_size);
            m->legacy_params (m, h->params, s->module_version, new_params, labs(m->version()));

            free (h->params);
            h->params = new_params;
          }

          dev.history_end++;
          dev.history = g_list_append(dev.history, h);
          break;
        }
        modules = g_list_next(modules);
      }
      stls = g_list_next(stls);
    }
  }

  dt_dev_pixelpipe_set_input(&pipe, &dev, (float *)buf.buf, buf.width, buf.height, 1.0);
  dt_dev_pixelpipe_create_nodes(&pipe, &dev);
  dt_dev_pixelpipe_synch_all(&pipe, &dev);
  dt_dev_pixelpipe_get_dimensions(&pipe, &dev, pipe.iwidth, pipe.iheight, &pipe.processed_width, &pipe.processed_height);
  if(filter)
  {
    if(!strncmp(filter, "pre:", 4))
      dt_dev_pixelpipe_disable_after(&pipe, filter+4);
    if(!strncmp(filter, "post:", 5))
      dt_dev_pixelpipe_disable_before(&pipe, filter+5);
  }
  dt_show_times(&start, "[export] creating pixelpipe", NULL);

  // find output color profile for this image:
  int sRGB = 1;
  gchar *overprofile = dt_conf_get_string("plugins/lighttable/export/iccprofile");
  if(overprofile && !strcmp(overprofile, "sRGB"))
  {
    sRGB = 1;
  }
  else if(!overprofile || !strcmp(overprofile, "image"))
  {
    GList *modules = dev.iop;
    dt_iop_module_t *colorout = NULL;
    while (modules)
    {
      colorout = (dt_iop_module_t *)modules->data;
      if(colorout->get_p && strcmp(colorout->op, "colorout") == 0)
      {
        const char *iccprofile = colorout->get_p(colorout->params, "iccprofile");
        if(!strcmp(iccprofile, "sRGB")) sRGB = 1;
        else sRGB = 0;
      }
      modules = g_list_next(modules);
    }
  }
  else
  {
    sRGB = 0;
  }
  g_free(overprofile);

  // get only once at the beginning, in case the user changes it on the way:
  const gboolean high_quality_processing = ((format_params->max_width  == 0 || format_params->max_width  >= pipe.processed_width ) &&
      (format_params->max_height == 0 || format_params->max_height >= pipe.processed_height)) ? FALSE :
      high_quality;
  const int width  = high_quality_processing ? 0 : format_params->max_width;
  const int height = high_quality_processing ? 0 : format_params->max_height;
  const double scalex = width  > 0 ? fminf(width /(double)pipe.processed_width,  1.0) : 1.0;
  const double scaley = height > 0 ? fminf(height/(double)pipe.processed_height, 1.0) : 1.0;
  const double scale = fminf(scalex, scaley);
  int processed_width  = scale*pipe.processed_width  + .5f;
  int processed_height = scale*pipe.processed_height + .5f;
  const int bpp = format->bpp(format_params);

  // downsampling done last, if high quality processing was requested:
  uint8_t *outbuf = pipe.backbuf;
  uint8_t *moutbuf = NULL; // keep track of alloc'ed memory
  dt_get_times(&start);
  if(high_quality_processing)
  {
    dt_dev_pixelpipe_process_no_gamma(&pipe, &dev, 0, 0, processed_width, processed_height, scale);
    const double scalex = format_params->max_width  > 0 ? fminf(format_params->max_width /(double)pipe.processed_width,  1.0) : 1.0;
    const double scaley = format_params->max_height > 0 ? fminf(format_params->max_height/(double)pipe.processed_height, 1.0) : 1.0;
    const double scale = fminf(scalex, scaley);
    processed_width  = scale*pipe.processed_width  + .5f;
    processed_height = scale*pipe.processed_height + .5f;
    moutbuf = (uint8_t *)dt_alloc_align(64, (size_t)sizeof(float)*processed_width*processed_height*4);
    outbuf = moutbuf;
    // now downscale into the new buffer:
    dt_iop_roi_t roi_in, roi_out;
    roi_in.x = roi_in.y = roi_out.x = roi_out.y = 0;
    roi_in.scale = 1.0;
    roi_out.scale = scale;
    roi_in.width = pipe.processed_width;
    roi_in.height = pipe.processed_height;
    roi_out.width = processed_width;
    roi_out.height = processed_height;
    dt_iop_clip_and_zoom((float *)outbuf, (float *)pipe.backbuf, &roi_out, &roi_in, processed_width, pipe.processed_width);
  }
  else
  {
    // do the processing (8-bit with special treatment, to make sure we can use openmp further down):
    if(bpp == 8)
      dt_dev_pixelpipe_process(&pipe, &dev, 0, 0, processed_width, processed_height, scale);
    else
      dt_dev_pixelpipe_process_no_gamma(&pipe, &dev, 0, 0, processed_width, processed_height, scale);
    outbuf = pipe.backbuf;
  }
  dt_show_times(&start, thumbnail_export ? "[dev_process_thumbnail] pixel pipeline processing" : "[dev_process_export] pixel pipeline processing", NULL);

  // downconversion to low-precision formats:
  if(bpp == 8)
  {
    if(display_byteorder)
    {
      if(high_quality_processing)
      {
        const float *const inbuf = (float *)outbuf;
        for(size_t k=0; k<(size_t)processed_width*processed_height; k++)
        {
          // convert in place, this is unfortunately very serial..
          const uint8_t r = CLAMP(inbuf[4*k+2]*0xff, 0, 0xff);
          const uint8_t g = CLAMP(inbuf[4*k+1]*0xff, 0, 0xff);
          const uint8_t b = CLAMP(inbuf[4*k+0]*0xff, 0, 0xff);
          outbuf[4*k+0] = r;
          outbuf[4*k+1] = g;
          outbuf[4*k+2] = b;
        }
      }
      // else processing output was 8-bit already, and no need to swap order
    }
    else // need to flip 
    {
      // ldr output: char
      if(high_quality_processing)
      {
        const float *const inbuf = (float *)outbuf;
        for(size_t k=0; k<(size_t)processed_width*processed_height; k++)
        {
          // convert in place, this is unfortunately very serial..
          const uint8_t r = CLAMP(inbuf[4*k+0]*0xff, 0, 0xff);
          const uint8_t g = CLAMP(inbuf[4*k+1]*0xff, 0, 0xff);
          const uint8_t b = CLAMP(inbuf[4*k+2]*0xff, 0, 0xff);
          outbuf[4*k+0] = r;
          outbuf[4*k+1] = g;
          outbuf[4*k+2] = b;
        }
      }
      else
      { // !display_byteorder, need to swap:
        uint8_t *const buf8 = pipe.backbuf;
#ifdef _OPENMP
#pragma omp parallel for default(none) shared(processed_width, processed_height) schedule(static)
#endif
        // just flip byte order
        for(size_t k=0; k<(size_t)processed_width*processed_height; k++)
        {
          uint8_t tmp = buf8[4*k+0];
          buf8[4*k+0] = buf8[4*k+2];
          buf8[4*k+2] = tmp;
        }
      }
    }
  }
  else if(bpp == 16)
  {
    // uint16_t per color channel
    float    *buff  = (float *)   outbuf;
    uint16_t *buf16 = (uint16_t *)outbuf;
    for(int y=0; y<processed_height; y++) for(int x=0; x<processed_width ; x++)
      {
        // convert in place
        const size_t k = (size_t)processed_width*y + x;
        for(int i=0; i<3; i++) buf16[4*k+i] = CLAMP(buff[4*k+i]*0x10000, 0, 0xffff);
      }
  }
  // else output float, no further harm done to the pixels :)

  format_params->width  = processed_width;
  format_params->height = processed_height;

  if(!ignore_exif)
  {
    int length;
    uint8_t exif_profile[65535]; // C++ alloc'ed buffer is uncool, so we waste some bits here.
    char pathname[PATH_MAX];
    gboolean from_cache = TRUE;
    dt_image_full_path(imgid, pathname, sizeof(pathname), &from_cache);
    // last param is dng mode, it's false here
    length = dt_exif_read_blob(exif_profile, pathname, imgid, sRGB, processed_width, processed_height, 0);

    res = format->write_image (format_params, filename, outbuf, exif_profile, length, imgid);
  }
  else
  {
    res = format->write_image (format_params, filename, outbuf, NULL, 0, imgid);
  }

  dt_dev_pixelpipe_cleanup(&pipe);
  dt_dev_cleanup(&dev);
  dt_mipmap_cache_read_release(darktable.mipmap_cache, &buf);
  dt_free_align(moutbuf);
  /* now write xmp into that container, if possible */
  if(copy_metadata && (format->flags(format_params) & FORMAT_FLAGS_SUPPORT_XMP)) {
    dt_exif_xmp_attach(imgid, filename);
    // no need to cancel the export if this fail
  }


  if(!thumbnail_export && strcmp(format->mime(format_params), "memory"))
  {
    dt_control_signal_raise(darktable.signals,DT_SIGNAL_IMAGE_EXPORT_TMPFILE,imgid,filename,format,format_params,storage,storage_params);
  }
  return res;
}
Пример #15
0
void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
             void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
{
  dt_iop_grain_data_t *data = (dt_iop_grain_data_t *)piece->data;

  unsigned int hash = _hash_string(piece->pipe->image.filename) % (int)fmax(roi_out->width * 0.3, 1.0);

  const int ch = piece->colors;
  // Apply grain to image
  const double strength = (data->strength / 100.0);
  const double octaves = 3;
  // double zoom=1.0+(8*(data->scale/100.0));
  const double wd = fminf(piece->buf_in.width, piece->buf_in.height);
  const double zoom = (1.0 + 8 * data->scale / 100) / 800.0;
  const int filter = fabsf(roi_out->scale - 1.0f) > 0.01;
  // filter width depends on world space (i.e. reverse wd norm and roi->scale, as well as buffer input to
  // pixelpipe iscale)
  const double filtermul = piece->iscale / (roi_out->scale * wd);
  const float fib1 = 34.0, fib2 = 21.0;
  const float fib1div2 = fib1 / fib2;

#ifdef _OPENMP
#pragma omp parallel for default(none) shared(data, hash)
#endif
  for(int j = 0; j < roi_out->height; j++)
  {
    float *in = ((float *)ivoid) + (size_t)roi_out->width * j * ch;
    float *out = ((float *)ovoid) + (size_t)roi_out->width * j * ch;
    const double wy = (roi_out->y + j) / roi_out->scale;
    const double y = wy / wd;
    // y: normalized to shorter side of image, so with pixel aspect = 1.

    for(int i = 0; i < roi_out->width; i++)
    {
      // calculate x, y in a resolution independent way:
      // wx,wy: worldspace in full image pixel coords:
      const double wx = (roi_out->x + i) / roi_out->scale;
      // x: normalized to shorter side of image, so with pixel aspect = 1.
      const double x = wx / wd;
      //  double noise=_perlin_2d_noise(x, y, octaves,0.25, zoom)*1.5;
      double noise = 0.0;
      if(filter)
      {
        // if zoomed out a lot, use rank-1 lattice downsampling
        for(int l = 0; l < fib2; l++)
        {
          float px = l / fib2, py = l * fib1div2;
          py -= (int)py;
          float dx = px * filtermul, dy = py * filtermul;
          noise += (1.0 / fib2) * _simplex_2d_noise(x + dx + hash, y + dy, octaves, 1.0, zoom);
        }
      }
      else
      {
        noise = _simplex_2d_noise(x + hash, y, octaves, 1.0, zoom);
      }

      out[0] = in[0] + dt_lut_lookup_2d_1c(data->grain_lut, (noise * strength) * GRAIN_LIGHTNESS_STRENGTH_SCALE, in[0] / 100.0f);
      out[1] = in[1];
      out[2] = in[2];
      out[3] = in[3];

      out += ch;
      in += ch;
    }
  }
}
Пример #16
0
/*
** Creates a MD5OpenGLMesh from an md5file
*/ 
static int MD5OpenGLMeshCreateWithFile(
	MD5OpenGLMesh** glmesh, 
	const char* filename
)
{
	FxsMD5Mesh* md5mesh = NULL;
	FxsMD5SubMesh* md5subMesh = NULL;
	FxsMD5Weight* md5weight = NULL;
	FxsMD5Vertex* md5vertex = NULL;
	FxsMD5Face* md5face = NULL;
	FxsMD5Joint* md5joint = NULL;
	FxsVector4 weightPosition; 				/* transformed weight position */
	FxsVector3* vertPosition;
	unsigned int count = 0; 				/* counts the vertices loaded */
	unsigned int* vertexIds = NULL; 		/* vertex indices of md5face */
	int i = 0, j = 0, k = 0, l = 0; 	 	/* loop variables */

	if (!FxsMD5MeshCreateWithFile(&md5mesh, filename))
	{
		sprintf(errMsg, "Warning: could not load md5mesh: %s", filename);
		ERR_MSG(errMsg);
		return 0;
	}

	*glmesh = (MD5OpenGLMesh*)malloc(sizeof(MD5OpenGLMesh));

	if (!glmesh) 
	{
		sprintf(
			errMsg,
			"Warning: malloc for MD5OpenGL mesh failed. Could not load md5mesh: %s", 
			filename
		);
	    ERR_MSG(errMsg)
		FxsMD5MeshDestroy(&md5mesh);
		return 0;
	}

	/* prepare gl mesh */
	memset(*glmesh, 0, sizeof(MD5OpenGLMesh));
	(*glmesh)->md5mesh = md5mesh;  
	(*glmesh)->numSubMeshes = md5mesh->numSubMeshes;
	(*glmesh)->subMeshes = (MD5OpenGLSubMesh*)malloc(
			md5mesh->numSubMeshes*sizeof(MD5OpenGLSubMesh)
		);

	if (!(*glmesh)->subMeshes)
	{
		sprintf(
			errMsg, 
			"Warning: malloc failed. Could not load md5mesh: %s", 
			filename
		);

		ERR_MSG(errMsg);	
		FxsMD5MeshDestroy(&md5mesh);
		MD5OpenGLMeshDestroy(glmesh);
		return 0;
	}		

	memset(
		(*glmesh)->subMeshes, 
		0, 
		(*glmesh)->numSubMeshes*sizeof(MD5OpenGLSubMesh)
	);

	(*glmesh)->min.x = FLT_MAX;
	(*glmesh)->min.y = FLT_MAX;
	(*glmesh)->min.z = FLT_MAX;
	(*glmesh)->max.x = FLT_MIN;
	(*glmesh)->max.y = FLT_MIN;
	(*glmesh)->max.z = FLT_MIN;
	
	/* load the submeshes */
	for (i = 0; i < md5mesh->numSubMeshes; i++)       /* for each md5submesh */
	{
	  	md5subMesh = &md5mesh->meshes[i];

		/* alloc host memory for positions of this gl submesh */
		(*glmesh)->subMeshes[i].numPositions = 3*md5subMesh->numFaces;
		(*glmesh)->subMeshes[i].positionsHost = (FxsVector3*)malloc(
				3*md5subMesh->numFaces*sizeof(FxsVector3)
			);
		
		if (!(*glmesh)->subMeshes[i].positionsHost) 
		{
		    sprintf(
				errMsg, 
				"Warning: malloc failed. Could not load md5mesh: %s", 
				filename
			);
			
			ERR_MSG(errMsg);	
			FxsMD5MeshDestroy(&md5mesh);
			MD5OpenGLMeshDestroy(glmesh);
		}

		memset(
			(*glmesh)->subMeshes[i].positionsHost,
			0,
			3*md5subMesh->numFaces*sizeof(FxsVector3)
		);

		/* init the bounding box for the sub mesh */
		(*glmesh)->subMeshes[i].min.x = FLT_MAX;
		(*glmesh)->subMeshes[i].min.y = FLT_MAX;
		(*glmesh)->subMeshes[i].min.z = FLT_MAX;
		(*glmesh)->subMeshes[i].max.x = FLT_MIN;
		(*glmesh)->subMeshes[i].max.y = FLT_MIN;
		(*glmesh)->subMeshes[i].max.z = FLT_MIN;
		
		count = 0;

		for (j = 0; j < md5subMesh->numFaces; j++)    /* for each face of the 
													  ** submesh */ 
		{
			md5face = &md5subMesh->faces[j];
			vertexIds = &md5face->v1;
	
			for (k = 0; k < 3; k++)           /* for each vertex of the face */
			{
				md5vertex = &md5subMesh->vertices[vertexIds[k]];
				
				/* make the current vertex position zero */
				vertPosition = &(*glmesh)->subMeshes[i].positionsHost[count];
				FxsVector3MakeZero(vertPosition);
			
				for (l = 0; l < md5vertex->numWeights; l++) /* for each weight 
															** of the vertex */
				{
					md5weight = &md5subMesh->weights[md5vertex->weightId + l];
					md5joint = &md5mesh->currentPose.joints[md5weight->jointId];
					
					FxsMatrix4MultiplyVector3(
						&weightPosition, 
						&md5joint->transform,
						&md5weight->position
					);

					/* add up all weight positions to compute the final
					** vertex position.
					*/
					vertPosition->x += md5weight->value*weightPosition.x;
					vertPosition->y += md5weight->value*weightPosition.y;
					vertPosition->z += md5weight->value*weightPosition.z;
				}

				/* update the bounding box */
				(*glmesh)->subMeshes[i].min.x = fminf(
						(*glmesh)->subMeshes[i].min.x, vertPosition->x
					);

				(*glmesh)->subMeshes[i].min.y = fminf(
						(*glmesh)->subMeshes[i].min.y, vertPosition->y
					);

				(*glmesh)->subMeshes[i].min.z = fminf(
						(*glmesh)->subMeshes[i].min.z, vertPosition->z
					);
		
				(*glmesh)->subMeshes[i].max.x = fmaxf(
						(*glmesh)->subMeshes[i].max.x, vertPosition->x
					);

				(*glmesh)->subMeshes[i].max.y = fmaxf(
						(*glmesh)->subMeshes[i].max.y, vertPosition->y
					);

				(*glmesh)->subMeshes[i].max.z = fmaxf(
						(*glmesh)->subMeshes[i].max.z, vertPosition->z
					);

				count++;
			}	
		}
        
		(*glmesh)->min.x = fminf((*glmesh)->subMeshes[i].min.x, (*glmesh)->min.x);
		(*glmesh)->min.y = fminf((*glmesh)->subMeshes[i].min.y, (*glmesh)->min.y);
		(*glmesh)->min.z = fminf((*glmesh)->subMeshes[i].min.z, (*glmesh)->min.z);

		(*glmesh)->max.x = fmaxf((*glmesh)->subMeshes[i].max.x, (*glmesh)->max.x);
		(*glmesh)->max.y = fmaxf((*glmesh)->subMeshes[i].max.y, (*glmesh)->max.y);
		(*glmesh)->max.z = fmaxf((*glmesh)->subMeshes[i].max.z, (*glmesh)->max.z);

		/* initialize the opengl data for the sub mesh */
		glGenBuffers(1, &(*glmesh)->subMeshes[i].positions);
		glBindBuffer(GL_ARRAY_BUFFER, (*glmesh)->subMeshes[i].positions);  
		
		glBufferData(
			GL_ARRAY_BUFFER,
		 	sizeof(FxsVector3)*(*glmesh)->subMeshes[i].numPositions,
			(*glmesh)->subMeshes[i].positionsHost,
			GL_DYNAMIC_DRAW
		);
		
		glGenVertexArrays(1, &(*glmesh)->subMeshes[i].vao);
		glBindVertexArray((*glmesh)->subMeshes[i].vao);
		glBindBuffer(GL_ARRAY_BUFFER, (*glmesh)->subMeshes[i].positions);
		glEnableVertexAttribArray(0);
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	
		if (GL_NO_ERROR != glGetError()) 
		{
			sprintf(errMsg, "Warning: opengl failed. Could not load md5mesh: %s", filename);
			ERR_MSG(errMsg);	
			FxsMD5MeshDestroy(&md5mesh);
			MD5OpenGLMeshDestroy(glmesh);
			return 0;		    
		}
	}
	
	return 1;
}
Пример #17
0
static void THNN_(VolumetricMaxPooling_updateOutput_frame)(
  real *input_p, real *output_p, real *indz_p,
  long nslices, long itime, long iwidth, long iheight,
  long otime, long owidth, long oheight,
  int kT, int kW, int kH,
  int dT, int dW, int dH,
  int pT, int pW, int pH)
{
  long k;
#pragma omp parallel for private(k)
  for (k = 0; k < nslices; k++)
  {
    /* loop over output */
    long i, j, ti;
    for (ti = 0; ti < otime; ti++)
    {
      for (i = 0; i < oheight; i++)
      {
        for (j = 0; j < owidth; j++)
        {
          /* local pointers */

          long start_t = ti * dT - pT;
          long start_h = i * dH - pH;
          long start_w = j * dW - pW;

          long kernel_t = fminf(kT, kT + start_t);
          long kernel_h = fminf(kH, kH + start_h);
          long kernel_w = fminf(kW, kW + start_w);

          start_t = fmaxf(start_t, 0);
          start_h = fmaxf(start_h, 0);
          start_w = fmaxf(start_w, 0);

          real *ip = input_p + k * itime * iwidth * iheight
            + start_t * iwidth * iheight + start_h * iwidth + start_w;
          real *op = output_p + k * otime * owidth * oheight
            + ti * owidth * oheight + i * owidth + j;
          real *indzp = indz_p + k * otime * owidth * oheight
            + ti * owidth * oheight + i * owidth + j;

          /* compute local max: */
          real maxval = -THInf;
          int x,y,z;
          int mx, my, mz;

          for (z = 0; z < kernel_t; z++)
          {
            for (y = 0; y < kernel_h; y++)
            {
              for (x = 0; x < kernel_w; x++)
              {
                if ((start_t + z < itime) && (start_h + y < iheight) && (start_w + x < iwidth))
                {
                  real val = *(ip + z * iwidth * iheight + y * iwidth + x);
                  if (val > maxval)
                  {
                    maxval = val;
                    // Store indices w.r.t the kernel dimension
                    mz = z + (kT - kernel_t);
                    my = y + (kH - kernel_h);
                    mx = x + (kW - kernel_w);
                  }
                }
              }
            }
          }

          // set max values
          ((unsigned char*)(indzp))[0] = mz;
          ((unsigned char*)(indzp))[1] = my;
          ((unsigned char*)(indzp))[2] = mx;
          ((unsigned char*)(indzp))[3] = 0;

          /* set output to local max */
          *op = maxval;
        }
      }
    }
  }
}
Пример #18
0
/*
** updates the md5mesh of mesh according to the passed animation and the frame.
** updates geometry on host and opengl side according to the updated pose.
*/ 
static int MD5OpenGLMeshUpdatePoseWithAnimationFrame(
	MD5OpenGLMesh* mesh,
	const FxsMD5Animation* animation, 
	unsigned int frame
)
{
	int i = 0, j = 0, k = 0, l = 0;
	FxsMD5Mesh* md5mesh = mesh->md5mesh;
	FxsMD5SubMesh* md5submesh = NULL;
	FxsMD5Face* face = NULL;
	FxsMD5Vertex* vertex = NULL;
	FxsMD5Weight* weight = NULL;	
	FxsMD5Joint* joint = NULL;
	FxsVector3* vertPosition = NULL;
	FxsVector4 weightPosition;
	unsigned int* vertexIds = NULL;
	MD5OpenGLSubMesh* glsubmesh = NULL;
	int count = 0;	

	if (!FxsMD5MeshUpdatePoseWithAnimationFrame(mesh->md5mesh, animation, frame))
	{
		return 0;
	}

	mesh->min.x = FLT_MAX;
	mesh->min.y = FLT_MAX;
	mesh->min.z = FLT_MAX;
	mesh->max.x = FLT_MIN;
	mesh->max.y = FLT_MIN;
	mesh->max.z = FLT_MIN;

	/* for all submeshes of the md5mesh, let's update the host and opengl data
	** of the opengl submeshes geometry (positions ...)
	*/ 
	for (i = 0; i < md5mesh->numSubMeshes; i++) 
	{
		glsubmesh = &mesh->subMeshes[i]; 		
		md5submesh = &md5mesh->meshes[i];		
		count = 0;

		mesh->subMeshes[i].min.x = FLT_MAX;
		mesh->subMeshes[i].min.y = FLT_MAX;
		mesh->subMeshes[i].min.z = FLT_MAX;
		mesh->subMeshes[i].max.x = FLT_MIN;
		mesh->subMeshes[i].max.y = FLT_MIN;
		mesh->subMeshes[i].max.z = FLT_MIN;

		/* for each face in the md5submesh ... */
		for (j = 0; j < md5submesh->numFaces; j++) 
		{
			face = &md5submesh->faces[j];		
			vertexIds = &face->v1;
		
			/* ... update each vertex */
			for (k = 0; k < 3; k++)
			{
				vertex = &md5submesh->vertices[vertexIds[k]];

				/* make the current vertex position zero */
				vertPosition = &mesh->subMeshes[i].positionsHost[count];
				FxsVector3MakeZero(vertPosition);

				/* update the position of each vertex by interation over
				** each of its weights
				*/
				for (l = 0; l < vertex->numWeights; l++)
				{
					weight = &md5submesh->weights[vertex->weightId + l];	
					joint = &md5mesh->currentPose.joints[weight->jointId];		
					
					FxsMatrix4MultiplyVector3(
						&weightPosition, 
						&joint->transform,
						&weight->position
					);

					/* add up all weight positions to compute the final
					** vertex position.
					*/
					vertPosition->x += weight->value*weightPosition.x;
					vertPosition->y += weight->value*weightPosition.y;
					vertPosition->z += weight->value*weightPosition.z;					
				}	

				/* update the bounding box */
				mesh->subMeshes[i].min.x = fminf(
						mesh->subMeshes[i].min.x, vertPosition->x
					);

				mesh->subMeshes[i].min.y = fminf(
						mesh->subMeshes[i].min.y, vertPosition->y
					);

				mesh->subMeshes[i].min.z = fminf(
						mesh->subMeshes[i].min.z, vertPosition->z
					);
		
				mesh->subMeshes[i].max.x = fmaxf(
						mesh->subMeshes[i].max.x, vertPosition->x
					);

				mesh->subMeshes[i].max.y = fmaxf(
						mesh->subMeshes[i].max.y, vertPosition->y
					);

				mesh->subMeshes[i].max.z = fmaxf(
						mesh->subMeshes[i].max.z, vertPosition->z
					);

				count++;
			}
		}
		
		mesh->min.x = fminf(mesh->subMeshes[i].min.x, mesh->min.x);
		mesh->min.y = fminf(mesh->subMeshes[i].min.y, mesh->min.y);
		mesh->min.z = fminf(mesh->subMeshes[i].min.z, mesh->min.z);

		mesh->max.x = fmaxf(mesh->subMeshes[i].max.x, mesh->max.x);
		mesh->max.y = fmaxf(mesh->subMeshes[i].max.y, mesh->max.y);
		mesh->max.z = fmaxf(mesh->subMeshes[i].max.z, mesh->max.z);

		/* update the opengl data for the sub mesh */
		glBindBuffer(GL_ARRAY_BUFFER, mesh->subMeshes[i].positions);  
	
		glBufferSubData(
			GL_ARRAY_BUFFER,
			0,
		 	sizeof(FxsVector3)*mesh->subMeshes[i].numPositions,
			mesh->subMeshes[i].positionsHost
		);
		
//		glGenVertexArrays(1, &(*glmesh)->subMeshes[i].vao);
//		glBindVertexArray((*glmesh)->subMeshes[i].vao);
//		glBindBuffer(GL_ARRAY_BUFFER, (*glmesh)->subMeshes[i].positions);
//		glEnableVertexAttribArray(0);
//		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	
		if (GL_NO_ERROR != glGetError()) 
		{
			sprintf(errMsg, "Warning: opengl failed. Could not update md5mesh");
			ERR_MSG(errMsg);	
			return 0;		    
		}	
	}
	
	return 1;
}
void test2f(float x, float y)
{
  if (-tanf(x-y) != tanf(y-x))
    link_error ();

  if (-sinf(x-y) != sinf(y-x))
    link_error ();

  if (cosf(-x*y) != cosf(x*y))
    link_error ();

  if (cosf(x*-y) != cosf(x*y))
    link_error ();

  if (cosf(-x/y) != cosf(x/y))
    link_error ();

  if (cosf(x/-y) != cosf(x/y))
    link_error ();

  if (cosf(-fabsf(tanf(x/-y))) != cosf(tanf(x/y)))
    link_error ();

  if (cosf(y<10 ? -x : y) != cosf(y<10 ? x : y))
    link_error ();

  if (cosf(y<10 ? x : -y) != cosf(y<10 ? x : y))
    link_error ();

  if (cosf(y<10 ? -fabsf(x) : tanf(x<20 ? -x : -fabsf(y)))
      != cosf(y<10 ? x : tanf(x<20 ? x : y)))
    link_error ();

  if (cosf((y*=3, -x)) != cosf((y*=3,x)))
    link_error ();

  if (cosf((y*=2, -fabsf(tanf(x/-y)))) != cosf((y*=2,tanf(x/y))))
    link_error ();

  if (cosf(copysignf(x,y)) != cosf(x))
    link_error ();

  if (cosf(copysignf(-fabsf(x),y*=2)) != cosf((y*=2,x)))
    link_error ();

  if (hypotf (x, 0) != fabsf(x))
    link_error ();

  if (hypotf (0, x) != fabsf(x))
    link_error ();

  if (hypotf (x, x) != fabsf(x) * __builtin_sqrtf(2))
    link_error ();

  if (hypotf (-x, y) != hypotf (x, y))
    link_error ();

  if (hypotf (x, -y) != hypotf (x, y))
    link_error ();

  if (hypotf (-x, -y) != hypotf (x, y))
    link_error ();

  if (hypotf (fabsf(x), y) != hypotf (x, y))
    link_error ();

  if (hypotf (x, fabsf(y)) != hypotf (x, y))
    link_error ();

  if (hypotf (fabsf(x), fabsf(y)) != hypotf (x, y))
    link_error ();

  if (hypotf (-fabsf(-x), -fabsf(fabsf(fabsf(-y)))) != hypotf (x, y))
    link_error ();

  if (hypotf (-x, 0) != fabsf(x))
    link_error ();

  if (hypotf (-x, x) != fabsf(x) * __builtin_sqrtf(2))
    link_error ();

  if (hypotf (puref(x), -puref(x)) != fabsf(puref(x)) * __builtin_sqrtf(2))
    link_error ();

  if (hypotf (tanf(-x), tanf(-fabsf(y))) != hypotf (tanf(x), tanf(y)))
    link_error ();

  if (fminf (fmaxf(x,y),y) != y)
    link_error ();

  if (fminf (fmaxf(y,x),y) != y)
    link_error ();

  if (fminf (x,fmaxf(x,y)) != x)
    link_error ();
  
  if (fminf (x,fmaxf(y,x)) != x)
    link_error ();
  
  if (fmaxf (fminf(x,y),y) != y)
    link_error ();

  if (fmaxf (fminf(y,x),y) != y)
    link_error ();

  if (fmaxf (x,fminf(x,y)) != x)
    link_error ();
  
  if (fmaxf (x,fminf(y,x)) != x)
    link_error ();

  if ((__complex__ float) x != -(__complex__ float) (-x))
    link_error ();

  if (x+(x-y)*1i != -(-x+(y-x)*1i))
    link_error ();

  if (x+(x-y)*1i != -(-x-(x-y)*1i))
    link_error ();

  if (ccosf(tanf(x)+sinf(y)*1i) != ccosf(-tanf(-x)+-sinf(-y)*1i))
    link_error ();

  if (ccosf(tanf(x)+sinf(x-y)*1i) != ccosf(-tanf(-x)-sinf(y-x)*1i))
    link_error ();

  if (-5+x*1i != -~(5+x*1i))
    link_error ();

  if (tanf(x)+tanf(y)*1i != -~(tanf(-x)+tanf(y)*1i))
    link_error ();
}
Пример #20
0
Vector4 Vector4::lerp(const Vector4& a, const Vector4& b, float t)
{
	t = fmaxf(t, 0);
	t = fminf(t, 1);
	return Vector4(b.x*t + a.x*(1 - t), b.y*t + a.y*(1 - t), b.z*t + a.z*(1 - t), b.w*t + a.w*(1 - t));
}
Пример #21
0
static int dt_group_get_mask(dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form,
                             float **buffer, int *width, int *height, int *posx, int *posy)
{
  double start2;
  // we allocate buffers and values
  const guint nb = g_list_length(form->points);
  if(nb == 0) return 0;
  float *bufs[nb];
  int w[nb];
  int h[nb];
  int px[nb];
  int py[nb];
  int ok[nb];
  int states[nb];
  float op[nb];

  // and we get all masks
  GList *fpts = g_list_first(form->points);
  int pos = 0;
  int nb_ok = 0;
  while(fpts)
  {
    dt_masks_point_group_t *fpt = (dt_masks_point_group_t *)fpts->data;
    dt_masks_form_t *sel = dt_masks_get_from_id(module->dev, fpt->formid);
    if(sel)
    {
      ok[pos] = dt_masks_get_mask(module, piece, sel, &bufs[pos], &w[pos], &h[pos], &px[pos], &py[pos]);
      if(fpt->state & DT_MASKS_STATE_INVERSE)
      {
        start2 = dt_get_wtime();
        _inverse_mask(module, piece, sel, &bufs[pos], &w[pos], &h[pos], &px[pos], &py[pos]);
        if(darktable.unmuted & DT_DEBUG_PERF)
          dt_print(DT_DEBUG_MASKS, "[masks %s] inverse took %0.04f sec\n", sel->name, dt_get_wtime() - start2);
//         start2 = dt_get_wtime();
      }
      op[pos] = fpt->opacity;
      states[pos] = fpt->state;
      if(ok[pos]) nb_ok++;
    }
    fpts = g_list_next(fpts);
    pos++;
  }
  if(nb_ok == 0) return 0;

  // now we get the min, max, width, height of the final mask
  int l, r, t, b;
  l = t = INT_MAX;
  r = b = INT_MIN;
  for(int i = 0; i < nb; i++)
  {
    l = MIN(l, px[i]);
    t = MIN(t, py[i]);
    r = MAX(r, px[i] + w[i]);
    b = MAX(b, py[i] + h[i]);
  }
  *posx = l;
  *posy = t;
  *width = r - l;
  *height = b - t;

  // we allocate the buffer
  *buffer = malloc(sizeof(float) * (r - l) * (b - t));

  // and we copy each buffer inside, row by row
  for(int i = 0; i < nb; i++)
  {
    start2 = dt_get_wtime();
    if(states[i] & DT_MASKS_STATE_UNION)
    {
      for(int y = 0; y < h[i]; y++)
      {
        for(int x = 0; x < w[i]; x++)
        {
          (*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l]
              = fmaxf((*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l], bufs[i][y * w[i] + x] * op[i]);
        }
      }
    }
    else if(states[i] & DT_MASKS_STATE_INTERSECTION)
    {
      for(int y = 0; y < b - t; y++)
      {
        for(int x = 0; x < r - l; x++)
        {
          float b1 = (*buffer)[y * (r - l) + x];
          float b2 = 0.0f;
          if(y + t - py[i] >= 0 && y + t - py[i] < h[i] && x + l - px[i] >= 0 && x + l - px[i] < w[i])
            b2 = bufs[i][(y + t - py[i]) * w[i] + x + l - px[i]];
          if(b1 > 0.0f && b2 > 0.0f)
            (*buffer)[y * (r - l) + x] = fminf(b1, b2 * op[i]);
          else
            (*buffer)[y * (r - l) + x] = 0.0f;
        }
      }
    }
    else if(states[i] & DT_MASKS_STATE_DIFFERENCE)
    {
      for(int y = 0; y < h[i]; y++)
      {
        for(int x = 0; x < w[i]; x++)
        {
          float b1 = (*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l];
          float b2 = bufs[i][y * w[i] + x] * op[i];
          if(b1 > 0.0f && b2 > 0.0f) (*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l] = b1 * (1.0f - b2);
        }
      }
    }
    else if(states[i] & DT_MASKS_STATE_EXCLUSION)
    {
      for(int y = 0; y < h[i]; y++)
      {
        for(int x = 0; x < w[i]; x++)
        {
          float b1 = (*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l];
          float b2 = bufs[i][y * w[i] + x] * op[i];
          if(b1 > 0.0f && b2 > 0.0f)
            (*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l] = fmaxf((1.0f - b1) * b2, b1 * (1.0f - b2));
          else
            (*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l]
                = fmaxf((*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l], bufs[i][y * w[i] + x] * op[i]);
        }
      }
    }
    else // if we are here, this mean that we just have to copy the shape and null other parts
    {
      for(int y = 0; y < b - t; y++)
      {
        for(int x = 0; x < r - l; x++)
        {
          float b2 = 0.0f;
          if(y + t - py[i] >= 0 && y + t - py[i] < h[i] && x + l - px[i] >= 0 && x + l - px[i] < w[i])
            b2 = bufs[i][(y + t - py[i]) * w[i] + x + l - px[i]];
          (*buffer)[y * (r - l) + x] = b2 * op[i];
        }
      }
    }

    // and we free the buffer
    free(bufs[i]);
    if(darktable.unmuted & DT_DEBUG_PERF)
      dt_print(DT_DEBUG_MASKS, "[masks %d] combine took %0.04f sec\n", i, dt_get_wtime() - start2);
//     start2 = dt_get_wtime();
  }

  return 1;
}
Пример #22
0
Vector4 Vector4::min(const Vector4& a, const Vector4& b)
{
	return Vector4(fminf(a.x, b.x), fminf(a.y, b.y), fminf(a.z, b.z), fminf(a.w, b.w));
}
Пример #23
0
int main( int argc, char *argv[] )
{
	/* parameters of strings */
	double Gamma   = LOOP_RAD_POWER;	/* power radiated by loops */
	double c       = CUSPS_PER_LOOP;	/* cusps per loop */

	double p,epsilon,f,Gmu,alpha;
	double gammaAverage = 0, gammaMin = 0, gammaMax =0;
	char filename[FILENAME_MAX];
	FILE *fp;
	int i,j,k,l;

	/* read the command line */
	if (ReadCommandLine(argc,argv,&CLA)) return 1;
	f=CLA.f;

	/* read efficiency function */
	if (ReadEfficiencyFile(CLA)) return 2;
	
	snprintf( filename, sizeof( filename ), "gamma.dat");
	fp = fopen( filename, "w" );
	fprintf( fp,"%%     p           n           epsilon         Gmu       gammaAverage    gammaMin      gammaMax\n");
	for ( i = 0; i <  CLA.nepsilon; i++ )
	  {
	    epsilon=pow(10.0,CLA.logepsilonstart+i*(CLA.logepsilonend-CLA.logepsilonstart)/(CLA.nepsilon-1));
	    
	    for ( j = 0; j <  CLA.nGmu; j++ )
	      {
		Gmu=pow(10.0,CLA.logGmustart+j*(CLA.logGmuend-CLA.logGmustart)/(CLA.nGmu-1));
		alpha = epsilon * pow( Gamma * Gmu, CLA.n );
			       
		/* find the z's corresponding to those A's */
		if(findzofA(Gmu, alpha)) return 3;
		
		/* compute the rate derivative at those z's */
		if(finddRdz(Gmu, alpha, f, Gamma)) return 4;
			
		for ( k = 0; k <  CLA.np; k++ )
		  {
		    p=pow(10.0, CLA.logpstart+k*(CLA.logpend-CLA.logpstart)/(CLA.np));
		    
 		    fprintf(stdout,"%%Computing effective rate for Gmu=%e, epsilon=%e, p=%e\n ",Gmu, epsilon, p);
		    
		    /* Compute the rate of bursts */
		    gammaAverage=0.0;
		    gammaMin = 0.0;
		    gammaMax = 0.0;
		    for (l = 0; l < Namp-1; l++)
		      {
			Dlnz = (-log(zofA[l+1])+log(zofA[l]));
			gammaAverage += eff[l] * zofA[l] * dRdz[l] * Dlnz;
			gammaMin += fmaxf((eff[l]-Deff[l]),0.0) * zofA[l] * dRdz[l] * Dlnz;
			gammaMax += fminf((eff[l]+Deff[l]),1.0) * zofA[l] * dRdz[l] * Dlnz;
		      }
		    gammaAverage *= c/p;
		    gammaMin *= c/p;
		    gammaMax *= c/p;

		    fprintf( fp,"%e  %e  %e  %e  %e  %e  %e\n", p,CLA.n,epsilon,Gmu,gammaAverage,gammaMin,gammaMax);

		  }
				
	      }
	  }

	fclose( fp );

	free(amp);
	free(lnamp);
	free(eff);
	free(Deff);
	free(zofA);
	free(dzdA);
	free(dRdz);

	return 0;
}
Пример #24
0
void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *ivoid, void *ovoid, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out)
{
  dt_iop_highlights_data_t *data = (dt_iop_highlights_data_t *)piece->data;
  float *in;
  float *out;
  const int ch = piece->colors;

  const float clip = data->clip * fminf(piece->pipe->processed_maximum[0], fminf(piece->pipe->processed_maximum[1], piece->pipe->processed_maximum[2]));
  float inc[3], lch[3], lchc[3], lchi[3];

  switch(data->mode)
  {
    case DT_IOP_HIGHLIGHTS_LCH:
#ifdef _OPENMP
      #pragma omp parallel for schedule(dynamic) default(none) shared(ovoid, ivoid, roi_out, data, piece) private(in, out, inc, lch, lchc, lchi)
#endif
      for(int j=0; j<roi_out->height; j++)
      {
        out = (float *)ovoid + ch*roi_out->width*j;
        in  = (float *)ivoid + ch*roi_out->width*j;
        for(int i=0; i<roi_out->width; i++)
        {
          if(in[0] <= clip && in[1] <= clip && in[2] <= clip)
          {
            // fast path for well-exposed pixels.
            for(int c=0; c<3; c++) out[c] = in[c];
          }
          else
          {
            for(int c=0; c<3; c++) inc[c] = fminf(clip, in[c]);
            rgb_to_lch(in, lchi);
            rgb_to_lch(inc, lchc);
            lch[0] = lchc[0] + data->blendL * (lchi[0] - lchc[0]);
            lch[1] = lchc[1] + data->blendC * (lchi[1] - lchc[1]);
            lch[2] = lchc[2] + data->blendh * (lchi[2] - lchc[2]);
            lch_to_rgb(lch, out);
          }
          out += ch;
          in += ch;
        }
      }
      break;
    default:
    case DT_IOP_HIGHLIGHTS_CLIP:
#ifdef _OPENMP
      #pragma omp parallel for schedule(dynamic) default(none) shared(ovoid, ivoid, roi_out) private(in, out, inc, lch, lchc, lchi)
#endif
      for(int j=0; j<roi_out->height; j++)
      {
        out = (float *)ovoid + ch*roi_out->width*j;
        in  = (float *)ivoid + ch*roi_out->width*j;
        for(int i=0; i<roi_out->width; i++)
        {
          for(int c=0; c<3; c++) out[c] = fminf(clip, in[c]);
          out += ch;
          in += ch;
        }
      }
      break;
  }

  if(piece->pipe->mask_display)
    dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
}
Пример #25
0
 /// clamp each vector values
 Vec3 clamp(float min_v, float max_v) const {
     return Vec3( fminf( fmaxf(x, min_v), max_v),
                  fminf( fmaxf(y, min_v), max_v),
                  fminf( fmaxf(z, min_v), max_v));
 }
Пример #26
0
/* Minimum of input signals */
float tf_min(struct sampleclock sc, void **storage, float a, float b)
{
    return fminf(a, b);
}
Пример #27
0
static inline float min(float a, float b) {
    return fminf(a, b);
}
Пример #28
0
static void
auto_apply_presets(dt_develop_t *dev)
{
  const int imgid = dev->image_storage.id;

  if(imgid <= 0) return;
  int run = 0;
  const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, imgid);
  if(!(cimg->flags & DT_IMAGE_AUTO_PRESETS_APPLIED))
    run = 1;

  // flag was already set? only apply presets once in the lifetime of a history stack.
  // (the flag will be cleared when removing it)
  if(!run || cimg->id <= 0)
  {
    dt_image_cache_read_release(darktable.image_cache, cimg);
    return;
  }

  // keep locked, we want to be alone messing with the history of the poor fellow:
  dt_image_t *image = dt_image_cache_write_get(darktable.image_cache, cimg);
  // be extra sure that we don't mess up history in separate threads:
  dt_pthread_mutex_lock(&darktable.db_insert);

  // cleanup
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db),
                        "delete from memory.history",
                        NULL, NULL, NULL);
  const char *preset_table[2] = {"presets", "legacy_presets"};
  const int legacy = (image->flags & DT_IMAGE_NO_LEGACY_PRESETS) ? 0 : 1;
  char query[1024];
  snprintf(query, 1024,
           "insert into memory.history select ?1, 0, op_version, operation, op_params, enabled, blendop_params, blendop_version, multi_priority, multi_name "
           "from %s where autoapply=1 and "
           "?2 like model and ?3 like maker and ?4 like lens and "
           "?5 between iso_min and iso_max and "
           "?6 between exposure_min and exposure_max and "
           "?7 between aperture_min and aperture_max and "
           "?8 between focal_length_min and focal_length_max and "
           "(isldr = 0 or isldr=?9) order by writeprotect desc, "
           "length(model), length(maker), length(lens)", preset_table[legacy]);
  // query for all modules at once:
  sqlite3_stmt *stmt;
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL);
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
  DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, cimg->exif_model, strlen(cimg->exif_model), SQLITE_TRANSIENT);
  DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 3, cimg->exif_maker, strlen(cimg->exif_maker), SQLITE_TRANSIENT);
  DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 4, cimg->exif_lens,  strlen(cimg->exif_lens),  SQLITE_TRANSIENT);
  DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 5, fmaxf(0.0f, fminf(1000000, cimg->exif_iso)));
  DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 6, fmaxf(0.0f, fminf(1000000, cimg->exif_exposure)));
  DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 7, fmaxf(0.0f, fminf(1000000, cimg->exif_aperture)));
  DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 8, fmaxf(0.0f, fminf(1000000, cimg->exif_focal_length)));
  // 0: dontcare, 1: ldr, 2: raw
  DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 9, 2-dt_image_is_ldr(cimg));

  if(sqlite3_step(stmt) == SQLITE_DONE)
  {
    sqlite3_finalize(stmt);
    int cnt = 0;
    // count what we found:
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                                "select count(*) from memory.history",
                                -1, &stmt, NULL);
    if(sqlite3_step(stmt) == SQLITE_ROW)
    {
      // if there is anything..
      cnt = sqlite3_column_int(stmt, 0);
      sqlite3_finalize(stmt);
      // fprintf(stderr, "[auto_apply_presets] imageid %d found %d matching presets (legacy %d)\n", imgid, cnt, legacy);
      // advance the current history by that amount:
      DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                                  "update history set num=num+?1 where imgid=?2",
                                  -1, &stmt, NULL);
      DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, cnt);
      DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);

      if(sqlite3_step(stmt) == SQLITE_DONE)
      {
        // and finally prepend the rest with increasing numbers (starting at 0)
        sqlite3_finalize(stmt);
        DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                                    "insert into history select imgid, rowid-1, module, operation, op_params, enabled, "
                                    "blendop_params, blendop_version, multi_priority, multi_name from memory.history",
                                    -1, &stmt, NULL);
        sqlite3_step(stmt);
      }
    }
  }
  sqlite3_finalize(stmt);

  //  first time we are loading the image, try to import lightroom .xmp if any
  if (dev->image_loading)
    dt_lightroom_import(dev->image_storage.id, dev, TRUE);

  image->flags |= DT_IMAGE_AUTO_PRESETS_APPLIED | DT_IMAGE_NO_LEGACY_PRESETS;
  dt_pthread_mutex_unlock(&darktable.db_insert);

  // make sure these end up in the image_cache + xmp (sync through here if we set the flag)
  dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);
  dt_image_cache_read_release(darktable.image_cache, cimg);
}
Пример #29
0
//Chase firing
bool Enemy::chaseFire(b2Vec2 & rFireV)
{
	bool trigger = false;

	//Did we fire?
	if (fired_)
	{
		angry_ = fmaxf(angry_ - triggerSatisfaction_[brainStem_.weapon_training], 0);
		fired_ = false;
	}

	//Fire at player?
	if (play_)
	{
		b2Vec2 myPos = getPosition();
		b2Vec2 pPos = player_->getPosition();
		b2Vec2 between = (pPos - myPos);
		float dist = between.Length();

		//Fire if in visible range and 
		if (dist < visRange_[brainStem_.sensitivity] && chill_ > freezingPoint_)
		{
			rFireV = LJP(pPos, 100, 0, 2.0, 0); //*//Fire LJP const?
		}
	}

	//DECIDE TO FIRE
	float seePlayer = rFireV.Length();
	float ammo = (float)getWeaponBar() / (float)getWeaponBarMAX();

	//Otherwise, heat up, chill first
	if (seePlayer != 0)
	{
		orient(rFireV);
		if (chill_ != 0) chill_ = fminf(chill_ += seePlayer * 4 * moodMult_[brainStem_.aggression], 0);
		else angry_ = fminf(angry_ + seePlayer * moodMult_[brainStem_.aggression], angryMAX_);
	}

	//If we're mad enough and we can see the player, fire
	if (angry_ > boilingPoint_ && seePlayer != 0)
	{
		trigger = true;
	}

	//Reload if we're cool enough
	if (angry_ - boilingPoint_ > (angryMAX_ - boilingPoint_) * accuracy_[brainStem_.weapon_training] * moodMult_[brainStem_.aggression]) //*//weapon training, aggression
	{
		if (ammo < accuracy_[brainStem_.weapon_training]) //*// weapon training causes later reloads
			reup();
	}

	//Chill out when idle
	if (angry_ == 0 && seePlayer == 0)
	{
		chill_ -= 1 * moodMult_[brainStem_.inner_peace];

		if (chill_ <= freezingPoint_)
		{
			if (ammo < 1.f)
				reup();

			spin(-0.05f);
		}
	}
	chill_ = fmax(chill_, chillMIN_);

	return trigger;
}
Пример #30
0
// internal function: to avoid exif blob reading + 8-bit byteorder flag + high-quality override
int dt_imageio_export_with_flags(const uint32_t imgid, const char *filename,
                                 dt_imageio_module_format_t *format, dt_imageio_module_data_t *format_params,
                                 const int32_t ignore_exif, const int32_t display_byteorder,
                                 const gboolean high_quality, const gboolean upscale, const int32_t thumbnail_export,
                                 const char *filter, const gboolean copy_metadata,
                                 dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename,
                                 dt_iop_color_intent_t icc_intent,
                                 dt_imageio_module_storage_t *storage,
                                 dt_imageio_module_data_t *storage_params, int num, int total)
{
  dt_develop_t dev;
  dt_dev_init(&dev, 0);
  dt_dev_load_image(&dev, imgid);

  const int buf_is_downscaled
      = (thumbnail_export && dt_conf_get_bool("plugins/lighttable/low_quality_thumbnails"));

  dt_mipmap_buffer_t buf;
  if(buf_is_downscaled)
    dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, DT_MIPMAP_F, DT_MIPMAP_BLOCKING, 'r');
  else
    dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r');

  const dt_image_t *img = &dev.image_storage;

  if(!buf.buf || !buf.width || !buf.height)
  {
    fprintf(stderr, "allocation failed???\n");
    dt_control_log(_("image `%s' is not available!"), img->filename);
    goto error_early;
  }

  const int wd = img->width;
  const int ht = img->height;
  const float max_scale = upscale ? 100.0 : 1.0;

  int res = 0;

  dt_times_t start;
  dt_get_times(&start);
  dt_dev_pixelpipe_t pipe;
  res = thumbnail_export ? dt_dev_pixelpipe_init_thumbnail(&pipe, wd, ht)
                         : dt_dev_pixelpipe_init_export(&pipe, wd, ht, format->levels(format_params));
  if(!res)
  {
    dt_control_log(
        _("failed to allocate memory for %s, please lower the threads used for export or buy more memory."),
        thumbnail_export ? C_("noun", "thumbnail export") : C_("noun", "export"));
    goto error;
  }

  //  If a style is to be applied during export, add the iop params into the history
  if(!thumbnail_export && format_params->style[0] != '\0')
  {
    GList *style_items = dt_styles_get_item_list(format_params->style, TRUE, -1);
    if(!style_items)
    {
      dt_control_log(_("cannot find the style '%s' to apply during export."), format_params->style);
      goto error;
    }

    // remove everything above history_end
    GList *history = g_list_nth(dev.history, dev.history_end);
    while(history)
    {
      GList *next = g_list_next(history);
      dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(history->data);
      free(hist->params);
      free(hist->blend_params);
      free(history->data);
      dev.history = g_list_delete_link(dev.history, history);
      history = next;
    }

    // Add each params
    for(GList *iter = style_items; iter; iter = g_list_next(iter))
    {
      dt_style_item_t *s = (dt_style_item_t *)iter->data;

      for(GList *module = dev.iop; module; module = g_list_next(module))
      {
        dt_iop_module_t *m = (dt_iop_module_t *)module->data;

        if(!strcmp(m->op, s->operation))
        {
          dt_dev_history_item_t *h = malloc(sizeof(dt_dev_history_item_t));
          dt_iop_module_t *style_module = m;

          if((format_params->style_append && !(m->flags() & IOP_FLAGS_ONE_INSTANCE)) || m->multi_priority != s->multi_priority)
          {
            // dt_dev_module_duplicate() doesn't work here, it's trying too hard to be clever
            style_module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
            if(style_module && !dt_iop_load_module(style_module, m->so, m->dev))
            {
              style_module->instance = m->instance;
              style_module->multi_priority = s->multi_priority;
              snprintf(style_module->multi_name, sizeof(style_module->multi_name), "%s", s->name);
              dev.iop = g_list_insert_sorted(dev.iop, style_module, sort_plugins);
            }
            else
            {
              free(h);
              goto error;
            }
          }

          h->params = s->params;
          h->blend_params = s->blendop_params;
          h->enabled = s->enabled;
          h->module = style_module;
          h->multi_priority = s->multi_priority;
          g_strlcpy(h->multi_name, s->name, sizeof(h->multi_name));

          if(m->legacy_params && (s->module_version != m->version()))
          {
            void *new_params = malloc(m->params_size);
            m->legacy_params(m, h->params, s->module_version, new_params, labs(m->version()));

            free(h->params);
            h->params = new_params;
          }

          dev.history_end++;
          dev.history = g_list_append(dev.history, h);

          // make sure that dt_style_item_free doesn't free data we still use
          s->params = NULL;
          s->blendop_params = NULL;

          break;
        }
      }
    }
    g_list_free_full(style_items, dt_style_item_free);
  }

  dt_dev_pixelpipe_set_icc(&pipe, icc_type, icc_filename, icc_intent);
  dt_dev_pixelpipe_set_input(&pipe, &dev, (float *)buf.buf, buf.width, buf.height, buf.iscale);
  dt_dev_pixelpipe_create_nodes(&pipe, &dev);
  dt_dev_pixelpipe_synch_all(&pipe, &dev);

  if(filter)
  {
    if(!strncmp(filter, "pre:", 4)) dt_dev_pixelpipe_disable_after(&pipe, filter + 4);
    if(!strncmp(filter, "post:", 5)) dt_dev_pixelpipe_disable_before(&pipe, filter + 5);
  }

  dt_dev_pixelpipe_get_dimensions(&pipe, &dev, pipe.iwidth, pipe.iheight, &pipe.processed_width,
                                  &pipe.processed_height);

  dt_show_times(&start, "[export] creating pixelpipe", NULL);

  // find output color profile for this image:
  int sRGB = 1;
  if(icc_type == DT_COLORSPACE_SRGB)
  {
    sRGB = 1;
  }
  else if(icc_type == DT_COLORSPACE_NONE)
  {
    GList *modules = dev.iop;
    dt_iop_module_t *colorout = NULL;
    while(modules)
    {
      colorout = (dt_iop_module_t *)modules->data;
      if(colorout->get_p && strcmp(colorout->op, "colorout") == 0)
      {
        const dt_colorspaces_color_profile_type_t *type = colorout->get_p(colorout->params, "type");
        sRGB = (!type || *type == DT_COLORSPACE_SRGB);
        break; // colorout can't have > 1 instance
      }
      modules = g_list_next(modules);
    }
  }
  else
  {
    sRGB = 0;
  }

  // get only once at the beginning, in case the user changes it on the way:
  const gboolean high_quality_processing
      = ((format_params->max_width == 0 || format_params->max_width >= pipe.processed_width)
         && (format_params->max_height == 0 || format_params->max_height >= pipe.processed_height))
            ? FALSE
            : high_quality;

  const int width = format_params->max_width;
  const int height = format_params->max_height;
  const double scalex = width > 0 ? fminf(width / (double)pipe.processed_width, max_scale) : 1.0;
  const double scaley = height > 0 ? fminf(height / (double)pipe.processed_height, max_scale) : 1.0;
  const double scale = fminf(scalex, scaley);

  const int processed_width = scale * pipe.processed_width + .5f;
  const int processed_height = scale * pipe.processed_height + .5f;

  const int bpp = format->bpp(format_params);

  dt_get_times(&start);
  if(high_quality_processing)
  {
    /*
     * if high quality processing was requested, downsampling will be done
     * at the very end of the pipe (just before border and watermark)
     */
    dt_dev_pixelpipe_process_no_gamma(&pipe, &dev, 0, 0, processed_width, processed_height, scale);
  }
  else
  {
    // else, downsampling will be right after demosaic

    // so we need to turn temporarily disable in-pipe late downsampling iop.

    // find the finalscale module
    dt_dev_pixelpipe_iop_t *finalscale = NULL;
    {
      GList *nodes = g_list_last(pipe.nodes);
      while(nodes)
      {
        dt_dev_pixelpipe_iop_t *node = (dt_dev_pixelpipe_iop_t *)(nodes->data);
        if(!strcmp(node->module->op, "finalscale"))
        {
          finalscale = node;
          break;
        }
        nodes = g_list_previous(nodes);
      }
    }

    if(finalscale) finalscale->enabled = 0;

    // do the processing (8-bit with special treatment, to make sure we can use openmp further down):
    if(bpp == 8)
      dt_dev_pixelpipe_process(&pipe, &dev, 0, 0, processed_width, processed_height, scale);
    else
      dt_dev_pixelpipe_process_no_gamma(&pipe, &dev, 0, 0, processed_width, processed_height, scale);

    if(finalscale) finalscale->enabled = 1;
  }
  dt_show_times(&start, thumbnail_export ? "[dev_process_thumbnail] pixel pipeline processing"
                                         : "[dev_process_export] pixel pipeline processing",
                NULL);

  uint8_t *outbuf = pipe.backbuf;

  // downconversion to low-precision formats:
  if(bpp == 8)
  {
    if(display_byteorder)
    {
      if(high_quality_processing)
      {
        const float *const inbuf = (float *)outbuf;
        for(size_t k = 0; k < (size_t)processed_width * processed_height; k++)
        {
          // convert in place, this is unfortunately very serial..
          const uint8_t r = CLAMP(inbuf[4 * k + 2] * 0xff, 0, 0xff);
          const uint8_t g = CLAMP(inbuf[4 * k + 1] * 0xff, 0, 0xff);
          const uint8_t b = CLAMP(inbuf[4 * k + 0] * 0xff, 0, 0xff);
          outbuf[4 * k + 0] = r;
          outbuf[4 * k + 1] = g;
          outbuf[4 * k + 2] = b;
        }
      }
      // else processing output was 8-bit already, and no need to swap order
    }
    else // need to flip
    {
      // ldr output: char
      if(high_quality_processing)
      {
        const float *const inbuf = (float *)outbuf;
        for(size_t k = 0; k < (size_t)processed_width * processed_height; k++)
        {
          // convert in place, this is unfortunately very serial..
          const uint8_t r = CLAMP(inbuf[4 * k + 0] * 0xff, 0, 0xff);
          const uint8_t g = CLAMP(inbuf[4 * k + 1] * 0xff, 0, 0xff);
          const uint8_t b = CLAMP(inbuf[4 * k + 2] * 0xff, 0, 0xff);
          outbuf[4 * k + 0] = r;
          outbuf[4 * k + 1] = g;
          outbuf[4 * k + 2] = b;
        }
      }
      else
      { // !display_byteorder, need to swap:
        uint8_t *const buf8 = pipe.backbuf;
#ifdef _OPENMP
#pragma omp parallel for default(none) schedule(static)
#endif
        // just flip byte order
        for(size_t k = 0; k < (size_t)processed_width * processed_height; k++)
        {
          uint8_t tmp = buf8[4 * k + 0];
          buf8[4 * k + 0] = buf8[4 * k + 2];
          buf8[4 * k + 2] = tmp;
        }
      }
    }
  }
  else if(bpp == 16)
  {
    // uint16_t per color channel
    float *buff = (float *)outbuf;
    uint16_t *buf16 = (uint16_t *)outbuf;
    for(int y = 0; y < processed_height; y++)
      for(int x = 0; x < processed_width; x++)
      {
        // convert in place
        const size_t k = (size_t)processed_width * y + x;
        for(int i = 0; i < 3; i++) buf16[4 * k + i] = CLAMP(buff[4 * k + i] * 0x10000, 0, 0xffff);
      }
  }
  // else output float, no further harm done to the pixels :)

  format_params->width = processed_width;
  format_params->height = processed_height;

  if(!ignore_exif)
  {
    int length;
    uint8_t *exif_profile = NULL; // Exif data should be 65536 bytes max, but if original size is close to that,
                                  // adding new tags could make it go over that... so let it be and see what
                                  // happens when we write the image
    char pathname[PATH_MAX] = { 0 };
    gboolean from_cache = TRUE;
    dt_image_full_path(imgid, pathname, sizeof(pathname), &from_cache);
    // last param is dng mode, it's false here
    length = dt_exif_read_blob(&exif_profile, pathname, imgid, sRGB, processed_width, processed_height, 0);

    res = format->write_image(format_params, filename, outbuf, icc_type, icc_filename, exif_profile, length, imgid,
                              num, total);

    free(exif_profile);
  }
  else
  {
    res = format->write_image(format_params, filename, outbuf, icc_type, icc_filename, NULL, 0, imgid, num, total);
  }

  dt_dev_pixelpipe_cleanup(&pipe);
  dt_dev_cleanup(&dev);
  dt_mipmap_cache_release(darktable.mipmap_cache, &buf);

  /* now write xmp into that container, if possible */
  if(copy_metadata && (format->flags(format_params) & FORMAT_FLAGS_SUPPORT_XMP))
  {
    dt_exif_xmp_attach(imgid, filename);
    // no need to cancel the export if this fail
  }

  if(!thumbnail_export && strcmp(format->mime(format_params), "memory")
    && !(format->flags(format_params) & FORMAT_FLAGS_NO_TMPFILE))
  {
#ifdef USE_LUA
    //Synchronous calling of lua intermediate-export-image events
    dt_lua_lock();

    lua_State *L = darktable.lua_state.state;

    luaA_push(L, dt_lua_image_t, &imgid);

    lua_pushstring(L, filename);

    luaA_push_type(L, format->parameter_lua_type, format_params);
 
    if (storage)
      luaA_push_type(L, storage->parameter_lua_type, storage_params);
    else
      lua_pushnil(L);

    dt_lua_event_trigger(L, "intermediate-export-image", 4);
  
    dt_lua_unlock();
#endif

    dt_control_signal_raise(darktable.signals, DT_SIGNAL_IMAGE_EXPORT_TMPFILE, imgid, filename, format,
                            format_params, storage, storage_params);
  }

  return res;

error:
  dt_dev_pixelpipe_cleanup(&pipe);
error_early:
  dt_dev_cleanup(&dev);
  dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
  return 1;
}