void YmxExplodeParticleSystem::_ResetParticle(YmxParticle* p)
{
	p->x = m_Center.x;
	p->y = m_Center.y;
	if(m_RGBVariant == 0)
	{
		p->color = m_StartColor;
	}else {
		p->alpha = RESTRICT_RGB(m_StartColorA + GetRandomInteger(-m_RGBVariant, m_RGBVariant));
		p->red   = RESTRICT_RGB(m_StartColorR + GetRandomInteger(-m_RGBVariant, m_RGBVariant));
		p->green = RESTRICT_RGB(m_StartColorG + GetRandomInteger(-m_RGBVariant, m_RGBVariant));
		p->blue  = RESTRICT_RGB(m_StartColorB + GetRandomInteger(-m_RGBVariant, m_RGBVariant));
	}

	float theta = GetRandomFloat(m_StartAngle, m_EndAngle);
	float velocity = m_Velocity + GetRandomFloat(-m_VelocityVariant, m_VelocityVariant);

	float cosValue = CosFastByAngle(theta);
	float sinValue = SinFastByAngle(theta);

	p->velocity.x = velocity * cosValue * m_Delta;
	p->velocity.y = velocity * sinValue * m_Delta;

	p->acceleration.x = (m_Acceleration * cosValue + m_FieldAcceleration.x) * m_Delta;
	p->acceleration.y = (m_Acceleration * sinValue + m_FieldAcceleration.y) * m_Delta;

	p->life = m_ParLife + GetRandomFloat(-m_ParLifeVariant, m_ParLifeVariant);
}
void YmxCometParticleSystem::_ResetParticle(YmxParticle* p)
{
	p->x = m_Position.x;
	p->y = m_Position.y;

	if(m_RGBVariant == 0)
	{
		p->color = m_StartColor;
	}else {
		p->alpha = RESTRICT_RGB(m_StartColorA + GetRandomInteger(-m_RGBVariant, m_RGBVariant));
		p->red   = RESTRICT_RGB(m_StartColorR + GetRandomInteger(-m_RGBVariant, m_RGBVariant));
		p->green = RESTRICT_RGB(m_StartColorG + GetRandomInteger(-m_RGBVariant, m_RGBVariant));
		p->blue  = RESTRICT_RGB(m_StartColorB + GetRandomInteger(-m_RGBVariant, m_RGBVariant));
	}

	float theta = GetRandomFloat(0.0f, 360.0f);
	float sinMulDelta = SinFastByAngle(theta) * m_Delta;
	float cosMulDelta = CosFastByAngle(theta) * m_Delta;

	float velocity = m_Velocity + GetRandomFloat(-m_VelocityVariant, m_VelocityVariant);
	float acceleration = m_Acceleration + GetRandomFloat(-m_AccelerationVariant, m_AccelerationVariant);
	p->velocity.x = velocity * cosMulDelta;
	p->velocity.y = velocity * sinMulDelta;
	p->acceleration.x = acceleration * cosMulDelta;
	p->acceleration.y = acceleration * sinMulDelta;
	p->size = m_StartSize + GetRandomFloat(-m_SizeVariant, m_SizeVariant);
	p->life = m_ParLife + GetRandomFloat(-m_ParLifeVariant, m_ParLifeVariant);
}
void YmxExplodeParticleSystem::_ResetParticle(int index)
{
	m_ParVertexs[index].x = m_Center.x;
	m_ParVertexs[index].y = m_Center.y;
	m_ParVertexs[index].z = m_z;
	m_ParVertexs[index].size = m_StartSize + GetRandomFloat(-m_SizeVariant, m_SizeVariant);
	if(m_RGBVariant == 0)
	{
		m_ParVertexs[index].color = m_StartColor;
	}else {
		m_ParVertexs[index].alpha = RESTRICT_RGB(m_StartColorA + GetRandomInteger(-m_RGBVariant, m_RGBVariant));
		m_ParVertexs[index].red   = RESTRICT_RGB(m_StartColorR + GetRandomInteger(-m_RGBVariant, m_RGBVariant));
		m_ParVertexs[index].green = RESTRICT_RGB(m_StartColorG + GetRandomInteger(-m_RGBVariant, m_RGBVariant));
		m_ParVertexs[index].blue  = RESTRICT_RGB(m_StartColorB + GetRandomInteger(-m_RGBVariant, m_RGBVariant));
	}

	float theta = GetRandomFloat(m_StartAngle, m_EndAngle);
	float velocity = m_Velocity + GetRandomFloat(-m_VelocityVariant, m_VelocityVariant);

	float cosValue = CosFastByAngle(theta);
	float sinValue = SinFastByAngle(theta);

	m_ParAttributes[index].velocity.x = velocity * cosValue * m_Delta;
	m_ParAttributes[index].velocity.y = velocity * sinValue * m_Delta;

	m_ParAttributes[index].acceleration.x = (m_Acceleration * cosValue + m_FieldAcceleration.x) * m_Delta;
	m_ParAttributes[index].acceleration.y = (m_Acceleration * sinValue + m_FieldAcceleration.y) * m_Delta;

	m_ParAttributes[index].life = m_ParLife + GetRandomFloat(-m_ParLifeVariant, m_ParLifeVariant);
}
Example #4
0
void Draw(Bitmap *surface) {
	ClearBitmap(surface);

	if (pause_mode)
	{
		DrawText(surface, "PAUSE", 50, 180);
	} else {
		for(int i=0;i<NumberOfStars;i++)
		{
			DrawRLEBitmap(surface,sprites[stars[i].f],(stars[i].x),stars[i].y);

			stars[i].y+=stars[i].dy;
			if(stars[i].y>=(200))
			{
				stars[i].y=(0);
				stars[i].x=GetRandomInteger()%320;
				stars[i].f=(stars[i].f%7)+(GetRandomInteger()%6)*7;

			}
			const RLEBitmap sprite = *sprites[stars[i].f];
			const RLEBitmap spaceBitmap = *spacecraft[0];
			if (RectRectIntersection(stars[i].x, stars[i].y, sprite.width, sprite.height, pos_x, pos_y, spaceBitmap.width, spaceBitmap.height))
			{
				gameOver(surface, pos_x, pos_y);
			}
		}
	}

	DrawRLEBitmap(surface, spacecraft[dir+1], pos_x, pos_y);
}
Example #5
0
void Init(struct Gamestate* state)
{
	EnableDebugOutput(DEBUG_USART);
	printf("Init\r\n");

	InitializeLEDs();

	SetLEDs(0x01);
	SetLEDs(0x07);

#ifdef ACCELEROMETER
/*	InitializeAccelerometer();
	printf("Init Accelerometer: %s\r\n", PingAccelerometer() > 0 ? "OKAY" : "FAILED");
	CalibrateAccelerometer();*/
#endif

	for(int i=0;i<NumberOfStars;i++)
	{
		stars[i].x=GetRandomInteger()%360;
		stars[i].y=(GetRandomInteger()%200);

		int z=sqrti((NumberOfStars-1-i)*NumberOfStars)*1000/NumberOfStars;
		stars[i].dy=1;//6000*1200/(z+200);

		stars[i].f=(6-(z*7)/1000)+(GetRandomInteger()%6)*7;
	}
}
YMXCOLOR YmxSnowParticleSystem::_GetRandomColor()
{
	int r = GetRandomInteger(m_MinColorR, m_MaxColorR);
	int g = GetRandomInteger(m_MinColorG, m_MaxColorG);
	int b = GetRandomInteger(m_MinColorB, m_MaxColorB);
	int a = GetRandomInteger(m_MinColorA, m_MaxColorA);
	return YMX_ARGB(a, r, g, b);
}
void YmxCometParticleSystem::SetPosition(float x, float y)
{
	if(m_Style & _PS_COMIT_BURN_ONLY_ONMOVING)
	{
		if(TWO_FLOATS_EQUAL(x, m_Position.x) && TWO_FLOATS_EQUAL(y, m_Position.y)) return;
		m_Position.x = x;
		m_Position.y = y;

		YmxParticle *p;
		int i;
		if(m_bSupportPSize)
		{
			for (i = 0; i < m_Density; i++)
			{
				p = _GetFreeParticle();
				_ResetParticle(p);
				p->next = m_Particles;
				m_Particles = p;
				m_Count++;
			}
		}
		else {
			int groupIndex;
			for (i = 0; i < m_Density; i++)
			{
				p = _GetFreeParticle();
				_ResetParticle(p);
				groupIndex = GetRandomInteger(0, m_StartSizeRange);
				p->next = m_ParGroups[groupIndex].particles;
				m_ParGroups[groupIndex].particles = p;
				if(m_ParGroups[groupIndex].particles->next == NULL)
				{
					m_ParGroups[groupIndex].tail = p;
				}
				m_Count++;
			}
		}
	}
	else {
		m_Position.x = x;
		m_Position.y = y;
	}
}
void YmxSnowParticleSystem::_AddParticle(bool bOnBordary)
{
	YmxParticle *p = new YmxParticle;
	_ResetParticle(p, bOnBordary);
	p->next = NULL;

	if(m_bSupportPSize)
	{
		p->size = GetRandomFloat(m_MinSize, m_MaxSize);
		p->next = m_Particles;
		m_Particles = p;
	}
	else {
		int index = GetRandomInteger(0, m_psizeNum - 1);
		p->next = m_ParsGroups[index].particles;
		m_ParsGroups[index].particles = p;
	}
	m_Count++;
}
void YmxCometParticleSystem::_Update_Not_SupportPSize(float delta)
{
	int i;
	YmxParticle* p;
	int groupIndex;

	if(!(m_Style & _PS_COMIT_BURN_ONLY_ONMOVING))
	{
		for (i = 0; i < m_Density; i++)
		{
			p = _GetFreeParticle();
			_ResetParticle(p);
			groupIndex = GetRandomInteger(0, m_StartSizeRange);
			p->next = m_ParGroups[groupIndex].particles;
			m_ParGroups[groupIndex].particles = p;
			if(m_ParGroups[groupIndex].particles->next == NULL)
			{
				m_ParGroups[groupIndex].tail = p;
			}
			m_Count++;
		}
	}

	if(m_Style & _PS_SIZE_GRADIENT)
	{
		//Update Point Size
		if(m_ParGroupNum > 1)
		{
			m_elapseTimeSinceUpdatePSize += delta;
			if(m_elapseTimeSinceUpdatePSize > m_UpdatePSizeDelta)
			{
				m_elapseTimeSinceUpdatePSize = 0;

				// put the second smaller size Particle group to the tail of the first Particle Group
				if(m_ParGroups[m_ParGroupNum - 1].particles != NULL) 
					m_ParGroups[m_ParGroupNum - 1].tail->next = m_ParGroups[m_ParGroupNum - 2].particles;
				else 
					m_ParGroups[m_ParGroupNum - 1].particles = m_ParGroups[m_ParGroupNum - 2].particles;

				if(m_ParGroups[m_ParGroupNum - 2].particles != NULL)
					m_ParGroups[m_ParGroupNum - 1].tail = m_ParGroups[m_ParGroupNum - 2].tail;

				for(i = m_ParGroupNum - 3; i >= 0; i--)
				{
					m_ParGroups[i + 1].particles = m_ParGroups[i].particles;
					m_ParGroups[i + 1].tail = m_ParGroups[i].tail;
				}
				m_ParGroups[0].particles = NULL;
				m_ParGroups[0].tail = NULL;
			}
		}
	}

	for (i = 0; i < m_ParGroupNum; i++)
	{
		YmxParticle *p1 = m_ParGroups[i].particles, *p2 = NULL, *p3 = NULL;
		while(p1 != NULL)
		{
			if(p1->life < 0)
			{
				// Remove the particle from current Particle Group
				if(p2 == NULL)
				{
					m_ParGroups[i].particles = p1->next;
				}
				else {
					p2->next = p1->next;
				}
				p3 = p1;
				p1 = p1->next;
				if(p1 == NULL) m_ParGroups[i].tail = p2;

				// recycle the p3
				p3->next = m_FreeParticles;
				m_FreeParticles = p3;
				m_Count--;
			}
			else {
				p1->x += p1->velocity.x;
				p1->y += p1->velocity.y;
				p1->velocity += p1->acceleration;
				p1->life -= delta;

				if(m_Style & _PS_COLOR_GRADIENT && m_StartColor != m_EndColor)
				{
					p1->alpha = RESTRICT_RGB(p1->alpha + m_ColorIncA);
					p1->red   = RESTRICT_RGB(p1->red + m_ColorIncR);
					p1->green = RESTRICT_RGB(p1->green + m_ColorIncG);
					p1->blue  = RESTRICT_RGB(p1->blue + m_ColorIncB);
				}

				p2 = p1;
				p1 = p1->next;
			}
		}
	}

}
void RunNewOrder(){
  /*
     "NEW_ORDER": {
     "getWarehouseTaxRate": "SELECT W_TAX FROM WAREHOUSE WHERE W_ID = ?", # w_id
     "getDistrict": "SELECT D_TAX, D_NEXT_O_ID FROM DISTRICT WHERE D_ID = ? AND D_W_ID = ?", # d_id, w_id
     "getCustomer": "SELECT C_DISCOUNT, C_LAST, C_CREDIT FROM CUSTOMER WHERE C_W_ID = ? AND C_D_ID = ? AND C_ID = ?", # w_id, d_id, c_id
     "incrementNextOrderId": "UPDATE DISTRICT SET D_NEXT_O_ID = ? WHERE D_ID = ? AND D_W_ID = ?", # d_next_o_id, d_id, w_id
     "createOrder": "INSERT INTO ORDERS (O_ID, O_D_ID, O_W_ID, O_C_ID, O_ENTRY_D, O_CARRIER_ID, O_OL_CNT, O_ALL_LOCAL) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", # d_next_o_id, d_id, w_id, c_id, o_entry_d, o_carrier_id, o_ol_cnt, o_all_local
     "createNewOrder": "INSERT INTO NEW_ORDER (NO_O_ID, NO_D_ID, NO_W_ID) VALUES (?, ?, ?)", # o_id, d_id, w_id
     "getItemInfo": "SELECT I_PRICE, I_NAME, I_DATA FROM ITEM WHERE I_ID = ?", # ol_i_id
     "getStockInfo": "SELECT S_QUANTITY, S_DATA, S_YTD, S_ORDER_CNT, S_REMOTE_CNT, S_DIST_%02d FROM STOCK WHERE S_I_ID = ? AND S_W_ID = ?", # d_id, ol_i_id, ol_supply_w_id
     "updateStock": "UPDATE STOCK SET S_QUANTITY = ?, S_YTD = ?, S_ORDER_CNT = ?, S_REMOTE_CNT = ? WHERE S_I_ID = ? AND S_W_ID = ?", # s_quantity, s_order_cnt, s_remote_cnt, ol_i_id, ol_supply_w_id
     "createOrderLine": "INSERT INTO ORDER_LINE (OL_O_ID, OL_D_ID, OL_W_ID, OL_NUMBER, OL_I_ID, OL_SUPPLY_W_ID, OL_DELIVERY_D, OL_QUANTITY, OL_AMOUNT, OL_DIST_INFO) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", # o_id, d_id, w_id, ol_number, ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_dist_info
     }
   */

  LOG_INFO("-------------------------------------");

  int warehouse_id = GetRandomInteger(0, state.warehouse_count - 1);
  int district_id = GetRandomInteger(0, state.districts_per_warehouse - 1);
  //int customer_id = GetRandomInteger(0, state.customers_per_district);
  int o_ol_cnt = GetRandomInteger(orders_min_ol_cnt, orders_max_ol_cnt);
  //auto o_entry_ts = GetTimeStamp();

  std::vector<int> i_ids, i_w_ids, i_qtys;
  //bool o_all_local = true;

  for (auto ol_itr = 0; ol_itr < o_ol_cnt; ol_itr++) {
    i_ids.push_back(GetRandomInteger(0, state.item_count));
    bool remote = GetRandomBoolean(new_order_remote_txns);
    i_w_ids.push_back(warehouse_id);

    if(remote == true) {
      i_w_ids[ol_itr] = GetRandomIntegerExcluding(0, state.warehouse_count - 1, warehouse_id);
      //o_all_local = false;
    }

    i_qtys.push_back(GetRandomInteger(0, order_line_max_ol_quantity));
  }

  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();
  auto txn = txn_manager.BeginTransaction();
  std::unique_ptr<VarlenPool> pool(new VarlenPool(BACKEND_TYPE_MM));
  std::unique_ptr<executor::ExecutorContext> context(
      new executor::ExecutorContext(txn));

  // getWarehouseTaxRate

  std::vector<oid_t> warehouse_column_ids = {7}; // W_TAX

  // Create and set up index scan executor
  std::vector<oid_t> warehouse_key_column_ids = {0}; // W_ID
  std::vector<ExpressionType> warehouse_expr_types;
  std::vector<Value> warehouse_key_values;
  std::vector<expression::AbstractExpression *> runtime_keys;

  warehouse_expr_types.push_back(
      ExpressionType::EXPRESSION_TYPE_COMPARE_EQUAL);
  warehouse_key_values.push_back(ValueFactory::GetIntegerValue(warehouse_id));
  auto warehouse_pkey_index = warehouse_table->GetIndexWithOid(
      warehouse_table_pkey_index_oid);
  planner::IndexScanPlan::IndexScanDesc warehouse_index_scan_desc(
      warehouse_pkey_index, warehouse_key_column_ids, warehouse_expr_types,
      warehouse_key_values, runtime_keys);

  // Create plan node.
  auto predicate = nullptr;
  planner::IndexScanPlan warehouse_index_scan_node(warehouse_table, predicate,
                                                   warehouse_column_ids,
                                                   warehouse_index_scan_desc);
  executor::IndexScanExecutor warehouse_index_scan_executor(&warehouse_index_scan_node,
                                                            context.get());

  auto gwtr_lists_values = ExecuteTest(&warehouse_index_scan_executor);
  if(gwtr_lists_values.empty() == true) {
    LOG_ERROR("getWarehouseTaxRate failed");
    txn_manager.AbortTransaction();
    return;
  }

  auto w_tax = gwtr_lists_values[0][0];
  LOG_TRACE("W_TAX: %d", w_tax);

  // getDistrict

  std::vector<oid_t> district_column_ids = {8, 10}; // D_TAX, D_NEXT_O_ID

  // Create and set up index scan executor
  std::vector<oid_t> district_key_column_ids = {0, 1}; // D_ID, D_W_ID
  std::vector<ExpressionType> district_expr_types;
  std::vector<Value> district_key_values;

  district_expr_types.push_back(
      ExpressionType::EXPRESSION_TYPE_COMPARE_EQUAL);
  district_expr_types.push_back(
      ExpressionType::EXPRESSION_TYPE_COMPARE_EQUAL);
  district_key_values.push_back(ValueFactory::GetIntegerValue(district_id));
  district_key_values.push_back(ValueFactory::GetIntegerValue(warehouse_id));

  auto district_pkey_index = district_table->GetIndexWithOid(
      district_table_pkey_index_oid);
  planner::IndexScanPlan::IndexScanDesc district_index_scan_desc(
      district_pkey_index, district_key_column_ids, district_expr_types,
      district_key_values, runtime_keys);

  // Create plan node.
  planner::IndexScanPlan district_index_scan_node(district_table, predicate,
                                                  district_column_ids,
                                                  district_index_scan_desc);
  executor::IndexScanExecutor district_index_scan_executor(&district_index_scan_node,
                                                           context.get());

  auto gd_lists_values = ExecuteTest(&district_index_scan_executor);
  if(gd_lists_values.empty() == true) {
    LOG_ERROR("getDistrict failed");
    txn_manager.AbortTransaction();
    return;
  }

  auto d_tax = gd_lists_values[0][0];
  LOG_TRACE("D_TAX: %d", d_tax);
  auto d_next_o_id = gd_lists_values[0][1];
  LOG_TRACE("D_NEXT_O_ID: %d", d_next_o_id);

  // incrementNextOrderId

  txn_manager.CommitTransaction();

}
Example #11
0
bool RunStockLevel(const size_t &thread_id) {
  /*
     "STOCK_LEVEL": {
     "getOId": "SELECT D_NEXT_O_ID FROM DISTRICT WHERE D_W_ID = ? AND D_ID = ?",
     "getStockCount": "SELECT COUNT(DISTINCT(OL_I_ID)) FROM ORDER_LINE, STOCK  WHERE OL_W_ID = ? AND OL_D_ID = ? AND OL_O_ID < ? AND OL_O_ID >= ? AND S_W_ID = ? AND S_I_ID = OL_I_ID AND S_QUANTITY < ?
     }
   */
  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();
  auto txn = txn_manager.BeginTransaction();

  std::unique_ptr<executor::ExecutorContext> context(
    new executor::ExecutorContext(txn));

  // Prepare random data
  int w_id = GenerateWarehouseId(thread_id);
  int d_id = GetRandomInteger(0, state.districts_per_warehouse - 1);
  int threshold = GetRandomInteger(stock_min_threshold, stock_max_threshold);

  LOG_TRACE("getOId: SELECT D_NEXT_O_ID FROM DISTRICT WHERE D_W_ID = ? AND D_ID = ?");

  // Construct index scan executor
  std::vector<oid_t> district_column_ids = {COL_IDX_D_NEXT_O_ID};
  std::vector<oid_t> district_key_column_ids = {COL_IDX_D_W_ID, COL_IDX_D_ID};
  std::vector<ExpressionType> district_expr_types;
  std::vector<common::Value *> district_key_values;
  std::vector<expression::AbstractExpression *> runtime_keys;

  district_expr_types.push_back(ExpressionType::EXPRESSION_TYPE_COMPARE_EQUAL);
  district_key_values.push_back(common::ValueFactory::GetIntegerValue(w_id).Copy());
  district_expr_types.push_back(ExpressionType::EXPRESSION_TYPE_COMPARE_EQUAL);
  district_key_values.push_back(common::ValueFactory::GetIntegerValue(d_id).Copy());

  auto district_pkey_index = district_table->GetIndexWithOid(district_table_pkey_index_oid);
  planner::IndexScanPlan::IndexScanDesc district_index_scan_desc(
    district_pkey_index, district_key_column_ids, district_expr_types,
    district_key_values, runtime_keys
  );

  expression::AbstractExpression *predicate = nullptr;
  planner::IndexScanPlan district_index_scan_node(
    district_table, predicate,
    district_column_ids, district_index_scan_desc
  );
  executor::IndexScanExecutor district_index_scan_executor(&district_index_scan_node, context.get());

  auto districts = ExecuteRead(&district_index_scan_executor);
  if (txn->GetResult() != Result::RESULT_SUCCESS) {
    txn_manager.AbortTransaction(txn);
    return false;
  }
  if (districts.size() != 1) {
    LOG_ERROR("incorrect districts size : %lu", districts.size());
    PL_ASSERT(false);
  }

  common::Value * o_id = districts[0][0];

  LOG_TRACE("getStockCount: SELECT COUNT(DISTINCT(OL_I_ID)) FROM ORDER_LINE, STOCK  WHERE OL_W_ID = ? AND OL_D_ID = ? AND OL_O_ID < ? AND OL_O_ID >= ? AND S_W_ID = ? AND S_I_ID = OL_I_ID AND S_QUANTITY < ?");
  
  int max_o_id = common::ValuePeeker::PeekInteger(o_id);
  int min_o_id = max_o_id - 20;

  //////////////////////////////////////////////////////////////
  std::vector<oid_t> order_line_column_ids = {COL_IDX_OL_I_ID};
  std::vector<oid_t> order_line_key_column_ids = {COL_IDX_OL_W_ID, COL_IDX_OL_D_ID, COL_IDX_OL_O_ID};
  std::vector<ExpressionType> order_line_expr_types;
  order_line_expr_types.push_back(ExpressionType::EXPRESSION_TYPE_COMPARE_EQUAL);
  order_line_expr_types.push_back(ExpressionType::EXPRESSION_TYPE_COMPARE_EQUAL);
  order_line_expr_types.push_back(ExpressionType::EXPRESSION_TYPE_COMPARE_EQUAL);

  auto order_line_skey_index = order_line_table->GetIndexWithOid(order_line_table_skey_index_oid);
  
  //////////////////////////////////////////////////////////////
  std::vector<oid_t> stock_column_ids = {COL_IDX_S_QUANTITY};
  std::vector<oid_t> stock_key_column_ids = {COL_IDX_S_W_ID, COL_IDX_S_I_ID};
  std::vector<ExpressionType> stock_expr_types;
  stock_expr_types.push_back(ExpressionType::EXPRESSION_TYPE_COMPARE_EQUAL);
  stock_expr_types.push_back(ExpressionType::EXPRESSION_TYPE_COMPARE_EQUAL);
  
  auto stock_pkey_index = stock_table->GetIndexWithOid(stock_table_pkey_index_oid);


  //////////////////////////////////////////////////////////////
  std::unordered_set<int> distinct_items;
  
  for (int curr_o_id = min_o_id; curr_o_id < max_o_id; ++curr_o_id) {
    ////////////////////////////////////////////////////////////////
    /////////// Construct left table index scan ////////////////////
    ////////////////////////////////////////////////////////////////

    std::vector<common::Value *> order_line_key_values;
    
    order_line_key_values.push_back(common::ValueFactory::GetIntegerValue(w_id).Copy());
    order_line_key_values.push_back(common::ValueFactory::GetIntegerValue(d_id).Copy());
    order_line_key_values.push_back(common::ValueFactory::GetIntegerValue(curr_o_id).Copy());

    planner::IndexScanPlan::IndexScanDesc order_line_index_scan_desc(
      order_line_skey_index, order_line_key_column_ids, order_line_expr_types,
      order_line_key_values, runtime_keys);

    planner::IndexScanPlan order_line_index_scan_node(order_line_table,
      nullptr, order_line_column_ids, order_line_index_scan_desc);

    executor::IndexScanExecutor order_line_index_scan_executor(&order_line_index_scan_node, context.get());

    auto order_line_values = ExecuteRead(&order_line_index_scan_executor);
    
    if (txn->GetResult() != Result::RESULT_SUCCESS) {
      LOG_TRACE("abort transaction");
      txn_manager.AbortTransaction(txn);
      return false;
    }

    if (order_line_values.size() == 0) {
      LOG_TRACE("order line return size incorrect : %lu", order_line_values.size());
      continue;
    }

    auto item_id = order_line_values[0][0];

    LOG_TRACE("item_id: %s", item_id.GetInfo().c_str());

    //////////////////////////////////////////////////////////////////
    ///////////// Construct right table index scan ///////////////////
    //////////////////////////////////////////////////////////////////

    std::vector<common::Value *> stock_key_values;

    stock_key_values.push_back(common::ValueFactory::GetIntegerValue(w_id).Copy());
    stock_key_values.push_back(item_id);
    
    planner::IndexScanPlan::IndexScanDesc stock_index_scan_desc(
        stock_pkey_index, stock_key_column_ids, stock_expr_types,
        stock_key_values, runtime_keys);

    // Add predicate S_QUANTITY < threshold
    planner::IndexScanPlan stock_index_scan_node(stock_table, nullptr,
                                                 stock_column_ids,
                                                 stock_index_scan_desc);

    executor::IndexScanExecutor stock_index_scan_executor(&stock_index_scan_node, context.get());

    auto stock_values = ExecuteRead(&stock_index_scan_executor);

    if (txn->GetResult() != Result::RESULT_SUCCESS) {
      LOG_TRACE("abort transaction");
      txn_manager.AbortTransaction(txn);
      return false;
    }

    if (stock_values.size() == 0) {
      // LOG_ERROR("stock return size incorrect : %lu", order_line_values.size());
      continue;
    }

    auto quantity = stock_values[0][0];
    if (common::ValuePeeker::PeekInteger(quantity) < threshold) {
      distinct_items.insert(common::ValuePeeker::PeekInteger(item_id));
    }

  }
  LOG_TRACE("number of distinct items=%lu", distinct_items.size());

  PL_ASSERT(txn->GetResult() == Result::RESULT_SUCCESS);

  auto result = txn_manager.CommitTransaction(txn);

  if (result == Result::RESULT_SUCCESS) {
    return true;
  } else {
    return false;
  }

  return true;
}
Example #12
0
bool RunDelivery(const size_t &thread_id) {
  /*
   "DELIVERY": {
   "getNewOrder": "SELECT NO_O_ID FROM NEW_ORDER WHERE NO_D_ID = ? AND NO_W_ID =
   ? AND NO_O_ID > -1 LIMIT 1", #
   "deleteNewOrder": "DELETE FROM NEW_ORDER WHERE NO_D_ID = ? AND NO_W_ID = ?
   AND NO_O_ID = ?", # d_id, w_id, no_o_id
   "getCId": "SELECT O_C_ID FROM ORDERS WHERE O_ID = ? AND O_D_ID = ? AND O_W_ID
   = ?", # no_o_id, d_id, w_id
   "updateOrders": "UPDATE ORDERS SET O_CARRIER_ID = ? WHERE O_ID = ? AND O_D_ID
   = ? AND O_W_ID = ?", # o_carrier_id, no_o_id, d_id, w_id
   "updateOrderLine": "UPDATE ORDER_LINE SET OL_DELIVERY_D = ? WHERE OL_O_ID = ?
   AND OL_D_ID = ? AND OL_W_ID = ?", # o_entry_d, no_o_id, d_id, w_id
   "sumOLAmount": "SELECT SUM(OL_AMOUNT) FROM ORDER_LINE WHERE OL_O_ID = ? AND
   OL_D_ID = ? AND OL_W_ID = ?", # no_o_id, d_id, w_id
   "updateCustomer": "UPDATE CUSTOMER SET C_BALANCE = C_BALANCE + ? WHERE C_ID =
   ? AND C_D_ID = ? AND C_W_ID = ?", # ol_total, c_id, d_id, w_id
   }
   */

  LOG_TRACE("-------------------------------------");

  /////////////////////////////////////////////////////////
  // PREPARE ARGUMENTS
  /////////////////////////////////////////////////////////
  int warehouse_id = GenerateWarehouseId(thread_id);
  int o_carrier_id =
      GetRandomInteger(orders_min_carrier_id, orders_max_carrier_id);

  std::vector<expression::AbstractExpression *> runtime_keys;

  /////////////////////////////////////////////////////////
  // BEGIN TRANSACTION
  /////////////////////////////////////////////////////////

  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();

  auto txn = txn_manager.BeginTransaction(thread_id);

  std::unique_ptr<executor::ExecutorContext> context(
      new executor::ExecutorContext(txn));

  for (int d_id = 0; d_id < state.districts_per_warehouse; ++d_id) {
    LOG_TRACE(
        "getNewOrder: SELECT NO_O_ID FROM NEW_ORDER WHERE NO_D_ID = ? AND "
        "NO_W_ID = ? AND NO_O_ID > -1 LIMIT 1");

    // Construct index scan executor
    std::vector<oid_t> new_order_column_ids = {COL_IDX_NO_O_ID};
    std::vector<oid_t> new_order_key_column_ids = {
        COL_IDX_NO_D_ID, COL_IDX_NO_W_ID, COL_IDX_NO_O_ID};

    std::vector<ExpressionType> new_order_expr_types;

    new_order_expr_types.push_back(ExpressionType::COMPARE_EQUAL);
    new_order_expr_types.push_back(ExpressionType::COMPARE_EQUAL);
    new_order_expr_types.push_back(ExpressionType::COMPARE_GREATERTHAN);

    std::vector<type::Value> new_order_key_values;

    new_order_key_values.push_back(
        type::ValueFactory::GetIntegerValue(d_id).Copy());
    new_order_key_values.push_back(
        type::ValueFactory::GetIntegerValue(warehouse_id).Copy());
    new_order_key_values.push_back(
        type::ValueFactory::GetIntegerValue(-1).Copy());

    planner::IndexScanPlan::IndexScanDesc new_order_idex_scan_desc(
        new_order_table_pkey_index_oid, new_order_key_column_ids,
        new_order_expr_types, new_order_key_values, runtime_keys);

    planner::IndexScanPlan new_order_idex_scan_node(new_order_table, nullptr,
                                                    new_order_column_ids,
                                                    new_order_idex_scan_desc);

    executor::IndexScanExecutor new_order_index_scan_executor(
        &new_order_idex_scan_node, context.get());

    // Construct limit executor
    size_t limit = 1;
    size_t offset = 0;
    planner::LimitPlan limit_node(limit, offset);
    executor::LimitExecutor limit_executor(&limit_node, context.get());
    limit_executor.AddChild(&new_order_index_scan_executor);

    auto new_order_ids = ExecuteRead(&limit_executor);

    if (txn->GetResult() != ResultType::SUCCESS) {
      LOG_TRACE("abort transaction");
      txn_manager.AbortTransaction(txn);
      return false;
    }

    if (new_order_ids.size() == 0) {
      // TODO:  No orders for this district: skip it. Note: This must be
      // reported if > 1%
      continue;
    }

    assert(new_order_ids.size() == 1);
    assert(new_order_ids[0].size() == 1);

    // result: NO_O_ID
    auto no_o_id = new_order_ids[0][0];

    LOG_TRACE("no_o_id = %d", type::ValuePeeker::PeekInteger(no_o_id));

    LOG_TRACE(
        "getCId: SELECT O_C_ID FROM ORDERS WHERE O_ID = ? AND O_D_ID = ? AND "
        "O_W_ID = ?");

    std::vector<oid_t> orders_column_ids = {COL_IDX_O_C_ID};
    std::vector<oid_t> orders_key_column_ids = {COL_IDX_O_ID, COL_IDX_O_D_ID,
                                                COL_IDX_O_W_ID};

    std::vector<ExpressionType> orders_expr_types;

    orders_expr_types.push_back(ExpressionType::COMPARE_EQUAL);
    orders_expr_types.push_back(ExpressionType::COMPARE_EQUAL);
    orders_expr_types.push_back(ExpressionType::COMPARE_EQUAL);

    std::vector<type::Value> orders_key_values;

    orders_key_values.push_back(no_o_id);
    orders_key_values.push_back(
        type::ValueFactory::GetIntegerValue(d_id).Copy());
    orders_key_values.push_back(
        type::ValueFactory::GetIntegerValue(warehouse_id).Copy());

    planner::IndexScanPlan::IndexScanDesc orders_index_scan_desc(
        orders_table_pkey_index_oid, orders_key_column_ids, orders_expr_types,
        orders_key_values, runtime_keys);

    // Create the index scan plan node
    planner::IndexScanPlan orders_index_scan_node(
        orders_table, nullptr, orders_column_ids, orders_index_scan_desc);

    // Create the executors
    executor::IndexScanExecutor orders_index_scan_executor(
        &orders_index_scan_node, context.get());

    auto orders_ids = ExecuteRead(&orders_index_scan_executor);

    if (txn->GetResult() != ResultType::SUCCESS) {
      LOG_TRACE("abort transaction");
      txn_manager.AbortTransaction(txn);
      return false;
    }

    assert(orders_ids.size() == 1);
    assert(orders_ids[0].size() == 1);

    // Result: O_C_ID
    auto c_id = orders_ids[0][0];

    LOG_TRACE(
        "sumOLAmount: SELECT SUM(OL_AMOUNT) FROM ORDER_LINE WHERE OL_O_ID = ? "
        "AND OL_D_ID = ? AND OL_W_ID = ?");

    // Construct index scan executor
    std::vector<oid_t> order_line_column_ids = {COL_IDX_OL_AMOUNT};
    std::vector<oid_t> order_line_key_column_ids = {
        COL_IDX_OL_O_ID, COL_IDX_OL_D_ID, COL_IDX_OL_W_ID};

    std::vector<ExpressionType> order_line_expr_types;

    order_line_expr_types.push_back(ExpressionType::COMPARE_EQUAL);
    order_line_expr_types.push_back(ExpressionType::COMPARE_EQUAL);
    order_line_expr_types.push_back(ExpressionType::COMPARE_EQUAL);

    std::vector<type::Value> order_line_key_values;

    order_line_key_values.push_back(no_o_id);
    order_line_key_values.push_back(
        type::ValueFactory::GetIntegerValue(d_id).Copy());
    order_line_key_values.push_back(
        type::ValueFactory::GetIntegerValue(warehouse_id).Copy());

    planner::IndexScanPlan::IndexScanDesc order_line_index_scan_desc(
        order_line_table_pkey_index_oid, order_line_key_column_ids,
        order_line_expr_types, order_line_key_values, runtime_keys);

    planner::IndexScanPlan order_line_index_scan_node(
        order_line_table, nullptr, order_line_column_ids,
        order_line_index_scan_desc);

    executor::IndexScanExecutor order_line_index_scan_executor(
        &order_line_index_scan_node, context.get());

    auto order_line_index_scan_res =
        ExecuteRead(&order_line_index_scan_executor);

    if (txn->GetResult() != ResultType::SUCCESS) {
      LOG_TRACE("abort transaction");
      txn_manager.AbortTransaction(txn);
      return false;
    }

    double sum_res = 0.0;

    // Workaround: Externanl sum
    for (auto v : order_line_index_scan_res) {
      assert(v.size() == 1);
      sum_res += type::ValuePeeker::PeekDouble(v[0]);
    }

    auto ol_total = type::ValueFactory::GetDecimalValue(sum_res);

    LOG_TRACE(
        "deleteNewOrder: DELETE FROM NEW_ORDER WHERE NO_D_ID = ? AND NO_W_ID = "
        "? AND NO_O_ID = ?");

    // Construct index scan executor
    std::vector<oid_t> new_order_delete_column_ids = {0};

    std::vector<ExpressionType> new_order_delete_expr_types;

    new_order_delete_expr_types.push_back(ExpressionType::COMPARE_EQUAL);
    new_order_delete_expr_types.push_back(ExpressionType::COMPARE_EQUAL);
    new_order_delete_expr_types.push_back(ExpressionType::COMPARE_EQUAL);

    std::vector<type::Value> new_order_delete_key_values;

    new_order_delete_key_values.push_back(
        type::ValueFactory::GetIntegerValue(d_id).Copy());
    new_order_delete_key_values.push_back(
        type::ValueFactory::GetIntegerValue(warehouse_id).Copy());
    new_order_delete_key_values.push_back(no_o_id);

    planner::IndexScanPlan::IndexScanDesc new_order_delete_idex_scan_desc(
        new_order_table_pkey_index_oid, new_order_key_column_ids,
        new_order_delete_expr_types, new_order_delete_key_values, runtime_keys);

    // Create index scan plan node
    planner::IndexScanPlan new_order_delete_idex_scan_node(
        new_order_table, nullptr, new_order_delete_column_ids,
        new_order_delete_idex_scan_desc);

    // Create executors
    executor::IndexScanExecutor new_order_delete_index_scan_executor(
        &new_order_delete_idex_scan_node, context.get());

    // Construct delete executor
    planner::DeletePlan new_order_delete_node(new_order_table);

    executor::DeleteExecutor new_order_delete_executor(&new_order_delete_node,
                                                       context.get());

    new_order_delete_executor.AddChild(&new_order_delete_index_scan_executor);

    // Execute the query
    ExecuteDelete(&new_order_delete_executor);

    // Check if aborted
    if (txn->GetResult() != ResultType::SUCCESS) {
      LOG_TRACE("abort transaction");
      txn_manager.AbortTransaction(txn);
      return false;
    }

    LOG_TRACE(
        "updateOrders: UPDATE ORDERS SET O_CARRIER_ID = ? WHERE O_ID = ? AND "
        "O_D_ID = ? AND O_W_ID = ?");

    // Construct index scan executor
    std::vector<oid_t> orders_update_column_ids = {COL_IDX_O_CARRIER_ID};

    std::vector<type::Value> orders_update_key_values;

    orders_update_key_values.push_back(no_o_id);
    orders_update_key_values.push_back(
        type::ValueFactory::GetIntegerValue(d_id).Copy());
    orders_update_key_values.push_back(
        type::ValueFactory::GetIntegerValue(warehouse_id).Copy());

    planner::IndexScanPlan::IndexScanDesc orders_update_index_scan_desc(
        orders_table_pkey_index_oid, orders_key_column_ids, orders_expr_types,
        orders_update_key_values, runtime_keys);

    // Reuse the index scan desc created above since nothing different
    planner::IndexScanPlan orders_update_index_scan_node(
        orders_table, nullptr, orders_update_column_ids,
        orders_update_index_scan_desc);

    executor::IndexScanExecutor orders_update_index_scan_executor(
        &orders_update_index_scan_node, context.get());

    // Construct update executor
    TargetList orders_target_list;
    DirectMapList orders_direct_map_list;

    size_t orders_column_count = 8;
    for (oid_t col_itr = 0; col_itr < orders_column_count; col_itr++) {
      // Skip O_CARRIER_ID
      if (col_itr != COL_IDX_O_CARRIER_ID) {
        orders_direct_map_list.emplace_back(col_itr,
                                            std::make_pair(0, col_itr));
      }
    }
    type::Value orders_update_val =
        type::ValueFactory::GetIntegerValue(o_carrier_id).Copy();

    planner::DerivedAttribute carrier_id{
        expression::ExpressionUtil::ConstantValueFactory(orders_update_val)};
    orders_target_list.emplace_back(COL_IDX_O_CARRIER_ID, carrier_id);

    std::unique_ptr<const planner::ProjectInfo> orders_project_info(
        new planner::ProjectInfo(std::move(orders_target_list),
                                 std::move(orders_direct_map_list)));
    planner::UpdatePlan orders_update_node(orders_table,
                                           std::move(orders_project_info));

    executor::UpdateExecutor orders_update_executor(&orders_update_node,
                                                    context.get());

    orders_update_executor.AddChild(&orders_update_index_scan_executor);

    // Execute the query
    ExecuteUpdate(&orders_update_executor);

    if (txn->GetResult() != ResultType::SUCCESS) {
      LOG_TRACE("abort transaction");
      txn_manager.AbortTransaction(txn);
      return false;
    }

    LOG_TRACE(
        "updateOrderLine: UPDATE ORDER_LINE SET OL_DELIVERY_D = ? WHERE "
        "OL_O_ID = ? AND OL_D_ID = ? AND OL_W_ID = ?");

    // Construct index scan executor
    std::vector<oid_t> order_line_update_column_ids = {COL_IDX_OL_DELIVERY_D};

    std::vector<type::Value> order_line_update_key_values;

    order_line_update_key_values.push_back(no_o_id);
    order_line_update_key_values.push_back(
        type::ValueFactory::GetIntegerValue(d_id).Copy());
    order_line_update_key_values.push_back(
        type::ValueFactory::GetIntegerValue(warehouse_id).Copy());

    planner::IndexScanPlan::IndexScanDesc order_line_update_index_scan_desc(
        order_line_table_pkey_index_oid, order_line_key_column_ids,
        order_line_expr_types, order_line_update_key_values, runtime_keys);

    planner::IndexScanPlan order_line_update_index_scan_node(
        order_line_table, nullptr, order_line_update_column_ids,
        order_line_update_index_scan_desc);

    executor::IndexScanExecutor order_line_update_index_scan_executor(
        &order_line_update_index_scan_node, context.get());

    // Construct update executor
    TargetList order_line_target_list;
    DirectMapList order_line_direct_map_list;

    size_t order_line_column_count = 10;
    for (oid_t col_itr = 0; col_itr < order_line_column_count; col_itr++) {
      // Skip OL_DELIVERY_D
      if (col_itr != COL_IDX_OL_DELIVERY_D) {
        order_line_direct_map_list.emplace_back(col_itr,
                                                std::make_pair(0, col_itr));
      }
    }
    type::Value order_line_update_val =
        type::ValueFactory::GetTimestampValue(0).Copy();

    planner::DerivedAttribute delivery_id{
        expression::ExpressionUtil::ConstantValueFactory(
            order_line_update_val)};
    order_line_target_list.emplace_back(COL_IDX_OL_DELIVERY_D, delivery_id);

    std::unique_ptr<const planner::ProjectInfo> order_line_project_info(
        new planner::ProjectInfo(std::move(order_line_target_list),
                                 std::move(order_line_direct_map_list)));
    planner::UpdatePlan order_line_update_node(
        order_line_table, std::move(order_line_project_info));

    executor::UpdateExecutor order_line_update_executor(&order_line_update_node,
                                                        context.get());

    order_line_update_executor.AddChild(&order_line_update_index_scan_executor);

    ExecuteUpdate(&order_line_update_executor);

    if (txn->GetResult() != ResultType::SUCCESS) {
      LOG_TRACE("abort transaction");
      txn_manager.AbortTransaction(txn);
      return false;
    }

    LOG_TRACE(
        "updateCustomer: UPDATE CUSTOMER SET C_BALANCE = C_BALANCE + ? WHERE "
        "C_ID = ? AND C_D_ID = ? AND C_W_ID = ?");

    // Construct index scan executor
    std::vector<oid_t> customer_column_ids = {COL_IDX_C_BALANCE};
    std::vector<oid_t> customer_key_column_ids = {COL_IDX_C_ID, COL_IDX_C_D_ID,
                                                  COL_IDX_C_W_ID};

    std::vector<ExpressionType> customer_expr_types;

    customer_expr_types.push_back(ExpressionType::COMPARE_EQUAL);
    customer_expr_types.push_back(ExpressionType::COMPARE_EQUAL);
    customer_expr_types.push_back(ExpressionType::COMPARE_EQUAL);

    std::vector<type::Value> customer_key_values;

    customer_key_values.push_back(c_id);
    customer_key_values.push_back(
        type::ValueFactory::GetIntegerValue(d_id).Copy());
    customer_key_values.push_back(
        type::ValueFactory::GetIntegerValue(warehouse_id).Copy());

    planner::IndexScanPlan::IndexScanDesc customer_index_scan_desc(
        customer_table_pkey_index_oid, customer_key_column_ids,
        customer_expr_types, customer_key_values, runtime_keys);

    planner::IndexScanPlan customer_index_scan_node(
        customer_table, nullptr, customer_column_ids, customer_index_scan_desc);

    executor::IndexScanExecutor customer_index_scan_executor(
        &customer_index_scan_node, context.get());

    // Construct update executor
    TargetList customer_target_list;
    DirectMapList customer_direct_map_list;

    size_t customer_column_count = 21;
    for (oid_t col_itr = 0; col_itr < customer_column_count; col_itr++) {
      // Skip OL_DELIVERY_D
      if (col_itr != COL_IDX_C_BALANCE) {
        customer_direct_map_list.emplace_back(col_itr,
                                              std::make_pair(0, col_itr));
      }
    }

    // Expressions
    // Tuple value expression
    auto tuple_val_expr = expression::ExpressionUtil::TupleValueFactory(
        type::TypeId::INTEGER, 0, COL_IDX_C_BALANCE);
    // Constant value expression
    auto constant_val_expr =
        expression::ExpressionUtil::ConstantValueFactory(ol_total);
    // + operator expression
    auto plus_operator_expr = expression::ExpressionUtil::OperatorFactory(
        ExpressionType::OPERATOR_PLUS, type::TypeId::INTEGER, tuple_val_expr,
        constant_val_expr);

    planner::DerivedAttribute c_balance{plus_operator_expr};
    customer_target_list.emplace_back(COL_IDX_C_BALANCE, c_balance);

    std::unique_ptr<const planner::ProjectInfo> customer_project_info(
        new planner::ProjectInfo(std::move(customer_target_list),
                                 std::move(customer_direct_map_list)));
    planner::UpdatePlan customer_update_node(customer_table,
                                             std::move(customer_project_info));

    executor::UpdateExecutor customer_update_executor(&customer_update_node,
                                                      context.get());

    customer_update_executor.AddChild(&customer_index_scan_executor);

    // Execute the query
    ExecuteUpdate(&customer_update_executor);

    if (txn->GetResult() != ResultType::SUCCESS) {
      LOG_TRACE("abort transaction");
      txn_manager.AbortTransaction(txn);
      return false;
    }
  }

  assert(txn->GetResult() == ResultType::SUCCESS);

  auto result = txn_manager.CommitTransaction(txn);

  if (result == ResultType::SUCCESS) {
    LOG_TRACE("commit successfully");
    return true;
  } else {
    assert(result == ResultType::ABORTED || result == ResultType::FAILURE);
    return false;
  }
}
void YmxExplodeParticleSystem::_Update_Not_SupportPSize(float delta)
{
	int i;
	int groupIndex;
	if(!m_bStopped && m_Count < m_MaxCount)
	{
		for (i = 0; i < m_AppearNumPerDelta; i++)
		{
			YmxParticle *p = new YmxParticle;
			_ResetParticle(p);
			groupIndex = GetRandomInteger(0, m_StartSizeRange);
			p->next = m_ParGroups[groupIndex].particles;
			m_ParGroups[groupIndex].particles = p;
			if(m_ParGroups[groupIndex].particles->next == NULL)
			{
				m_ParGroups[groupIndex].tail = p;
			}
			m_Count++;
		}
	}

	if(m_Style & _PS_SIZE_GRADIENT)
	{
		//Update Point Size
		if(m_ParGroupNum > 1)
		{
			m_elapseTimeSinceUpdatePSize += delta;
			if(m_elapseTimeSinceUpdatePSize > m_UpdatePSizeDelta)
			{
				m_elapseTimeSinceUpdatePSize = 0;

				// put the second smaller size Particle group to the tail of the first Particle Group
				if(m_ParGroups[m_ParGroupNum - 1].particles != NULL) 
					m_ParGroups[m_ParGroupNum - 1].tail->next = m_ParGroups[m_ParGroupNum - 2].particles;
				else 
					m_ParGroups[m_ParGroupNum - 1].particles = m_ParGroups[m_ParGroupNum - 2].particles;

				if(m_ParGroups[m_ParGroupNum - 2].particles != NULL)
					m_ParGroups[m_ParGroupNum - 1].tail = m_ParGroups[m_ParGroupNum - 2].tail;

				for(i = m_ParGroupNum - 3; i >= 0; i--)
				{
					m_ParGroups[i + 1].particles = m_ParGroups[i].particles;
					m_ParGroups[i + 1].tail = m_ParGroups[i].tail;
				}
				m_ParGroups[0].particles = NULL;
				m_ParGroups[0].tail = NULL;
			}
		}
	}

	for (i = 0; i < m_ParGroupNum; i++)
	{
		YmxParticle *p1 = m_ParGroups[i].particles, *p2 = NULL, *p3 = NULL;
		while(p1 != NULL)
		{
			if(p1->life < 0)
			{
				// Remove the particle from current Particle Group
				if(p2 == NULL)
				{
					m_ParGroups[i].particles = p1->next;
				}
				else {
					p2->next = p1->next;
				}
				p3 = p1;
				p1 = p1->next;
				if(p1 == NULL) m_ParGroups[i].tail = p2;

				// If has stopped, then delete the particle
				// else reset the particle and put it to Heat Source particle group again
				if (m_bStopped)
				{
					delete p3;
					m_Count--;
				}
				else {
					_ResetParticle(p3);
					if(m_ParGroupNum > 1) {
						groupIndex = GetRandomInteger(0, m_StartSizeRange);
						p3->next = m_ParGroups[groupIndex].particles;
						m_ParGroups[groupIndex].particles = p3;
						if(p3->next == NULL)  
							m_ParGroups[groupIndex].tail = p3;
					}
				}
			}
			else {
				p1->x += p1->velocity.x;
				p1->y += p1->velocity.y;
				p1->velocity += p1->acceleration;
				p1->life -= delta;

				if(m_Style & _PS_COLOR_GRADIENT && m_StartColor != m_EndColor)
				{
					p1->alpha = RESTRICT_RGB(p1->alpha + m_ColorIncA);
					p1->red   = RESTRICT_RGB(p1->red + m_ColorIncR);
					p1->green = RESTRICT_RGB(p1->green + m_ColorIncG);
					p1->blue  = RESTRICT_RGB(p1->blue + m_ColorIncB);
				}

				p2 = p1;
				p1 = p1->next;
			}
		}
	}
}