Esempio n. 1
0
/*
==================
idInteraction::AddActiveInteraction

Create and add any necessary light and shadow triangles

If the model doesn't have any surfaces that need interactions
with this type of light, it can be skipped, but we might need to
instantiate the dynamic model to find out
==================
*/
void idInteraction::AddActiveInteraction( void ) {
	viewLight_t *	vLight;
	viewEntity_t *	vEntity;
	idScreenRect	shadowScissor;
	idScreenRect	lightScissor;
	idVec3			localLightOrigin;
	idVec3			localViewOrigin;

	vLight = lightDef->viewLight;
	vEntity = entityDef->viewEntity;

	// do not waste time culling the interaction frustum if there will be no shadows
	if ( !HasShadows() ) {

		// use the entity scissor rectangle
		shadowScissor = vEntity->scissorRect;

	// culling does not seem to be worth it for static world models
	} else if ( entityDef->parms.hModel->IsStaticWorldModel() ) {

		// use the light scissor rectangle
		shadowScissor = vLight->scissorRect;

	} else {

		// try to cull the interaction
		// this will also cull the case where the light origin is inside the
		// view frustum and the entity bounds are outside the view frustum
		if ( CullInteractionByViewFrustum( tr.viewDef->viewFrustum ) ) {
			return;
		}

		// calculate the shadow scissor rectangle
		shadowScissor = CalcInteractionScissorRectangle( tr.viewDef->viewFrustum );
	}

	// get out before making the dynamic model if the shadow scissor rectangle is empty
	if ( shadowScissor.IsEmpty() ) {
		return;
	}

	// We will need the dynamic surface created to make interactions, even if the
	// model itself wasn't visible.  This just returns a cached value after it
	// has been generated once in the view.
	idRenderModel *model = R_EntityDefDynamicModel( entityDef );
	if ( model == NULL || model->NumSurfaces() <= 0 ) {
		return;
	}

	// the dynamic model may have changed since we built the surface list
	if ( !IsDeferred() && entityDef->dynamicModelFrameCount != dynamicModelFrameCount ) {
		FreeSurfaces();
	}
	dynamicModelFrameCount = entityDef->dynamicModelFrameCount;

	// actually create the interaction if needed, building light and shadow surfaces as needed
	if ( IsDeferred() ) {
		CreateInteraction( model );
	}

	R_GlobalPointToLocal( vEntity->modelMatrix, lightDef->globalLightOrigin, localLightOrigin );
	R_GlobalPointToLocal( vEntity->modelMatrix, tr.viewDef->renderView.vieworg, localViewOrigin );

	// calculate the scissor as the intersection of the light and model rects
	// this is used for light triangles, but not for shadow triangles
	lightScissor = vLight->scissorRect;
	lightScissor.Intersect( vEntity->scissorRect );

	bool lightScissorsEmpty = lightScissor.IsEmpty();

	// for each surface of this entity / light interaction
	for ( int i = 0; i < numSurfaces; i++ ) {
		surfaceInteraction_t *sint = &surfaces[i];

		// see if the base surface is visible, we may still need to add shadows even if empty
		if ( !lightScissorsEmpty && sint->ambientTris && sint->ambientTris->ambientViewCount == tr.viewCount ) {

			// make sure we have created this interaction, which may have been deferred
			// on a previous use that only needed the shadow
			if ( sint->lightTris == LIGHT_TRIS_DEFERRED ) {
				sint->lightTris = R_CreateLightTris( vEntity->entityDef, sint->ambientTris, vLight->lightDef, sint->shader, sint->cullInfo );
				R_FreeInteractionCullInfo( sint->cullInfo );
			}

			srfTriangles_t *lightTris = sint->lightTris;

			if ( lightTris ) {

				// try to cull before adding
				// FIXME: this may not be worthwhile. We have already done culling on the ambient,
				// but individual surfaces may still be cropped somewhat more
				if ( !R_CullLocalBox( lightTris->bounds, vEntity->modelMatrix, 5, tr.viewDef->frustum ) ) {

					// make sure the original surface has its ambient cache created
					srfTriangles_t *tri = sint->ambientTris;
					if ( !tri->ambientCache ) {
						if ( !R_CreateAmbientCache( tri, sint->shader->ReceivesLighting() ) ) {
							// skip if we were out of vertex memory
							continue;
						}
					}

					// reference the original surface's ambient cache
					lightTris->ambientCache = tri->ambientCache;

					// touch the ambient surface so it won't get purged
					vertexCache.Touch(lightTris->ambientCache);

					if (!lightTris->indexCache) {
						vertexCache.Alloc(lightTris->indexes, lightTris->numIndexes * sizeof(lightTris->indexes[0]), &lightTris->indexCache, true);
						vertexCache.Touch(lightTris->indexCache);
					}

					// add the surface to the light list

					const idMaterial *shader = sint->shader;
					R_GlobalShaderOverride(&shader);

					// there will only be localSurfaces if the light casts shadows and
					// there are surfaces with NOSELFSHADOW
					if ( sint->shader->Coverage() == MC_TRANSLUCENT ) {
						R_LinkLightSurf( &vLight->translucentInteractions, lightTris, 
							vEntity, lightDef, shader, lightScissor, false );
					} else if ( !lightDef->parms.noShadows && sint->shader->TestMaterialFlag(MF_NOSELFSHADOW) ) {
						R_LinkLightSurf( &vLight->localInteractions, lightTris, 
							vEntity, lightDef, shader, lightScissor, false );
					} else {
						R_LinkLightSurf( &vLight->globalInteractions, lightTris, 
							vEntity, lightDef, shader, lightScissor, false );
					}
				}
			}
		}

		srfTriangles_t *shadowTris = sint->shadowTris;

		// the shadows will always have to be added, unless we can tell they
		// are from a surface in an unconnected area
		if ( shadowTris ) {
			
			// check for view specific shadow suppression (player shadows, etc)
			if ( !r_skipSuppress.GetBool() ) {
				if ( entityDef->parms.suppressShadowInViewID &&
					entityDef->parms.suppressShadowInViewID == tr.viewDef->renderView.viewID ) {
					continue;
				}
				if ( entityDef->parms.suppressShadowInLightID &&
					entityDef->parms.suppressShadowInLightID == lightDef->parms.lightId ) {
					continue;
				}
			}

			// cull static shadows that have a non-empty bounds
			// dynamic shadows that use the turboshadow code will not have valid
			// bounds, because the perspective projection extends them to infinity
			if ( r_useShadowCulling.GetBool() && !shadowTris->bounds.IsCleared() ) {
				if ( R_CullLocalBox( shadowTris->bounds, vEntity->modelMatrix, 5, tr.viewDef->frustum ) ) {
					continue;
				}
			}

			// copy the shadow vertexes to the vertex cache if they have been purged

			// if we are using shared shadowVertexes and letting a vertex program fix them up,
			// get the shadowCache from the parent ambient surface
			if ( !shadowTris->shadowVertexes ) {
				// the data may have been purged, so get the latest from the "home position"
				shadowTris->shadowCache = sint->ambientTris->shadowCache;
			}

			// if we have been purged, re-upload the shadowVertexes
			if ( !shadowTris->shadowCache ) {
				if ( shadowTris->shadowVertexes ) {
					// each interaction has unique vertexes
					R_CreatePrivateShadowCache( shadowTris );
				} else {
					R_CreateVertexProgramShadowCache( sint->ambientTris );
					shadowTris->shadowCache = sint->ambientTris->shadowCache;
				}
				// if we are out of vertex cache space, skip the interaction
				if ( !shadowTris->shadowCache ) {
					continue;
				}
			}

			// touch the shadow surface so it won't get purged
			vertexCache.Touch( shadowTris->shadowCache );

			if ( !shadowTris->indexCache ) {
				vertexCache.Alloc( shadowTris->indexes, shadowTris->numIndexes * sizeof( shadowTris->indexes[0] ), &shadowTris->indexCache, true );
				vertexCache.Touch( shadowTris->indexCache );
			}

			// see if we can avoid using the shadow volume caps
			bool inside = R_PotentiallyInsideInfiniteShadow( sint->ambientTris, localViewOrigin, localLightOrigin );

			if ( sint->shader->TestMaterialFlag( MF_NOSELFSHADOW ) ) {
				R_LinkLightSurf( &vLight->localShadows,
					shadowTris, vEntity, lightDef, NULL, shadowScissor, inside );
			} else {
				R_LinkLightSurf( &vLight->globalShadows,
					shadowTris, vEntity, lightDef, NULL, shadowScissor, inside );
			}
		}
	}
}
Esempio n. 2
0
STDMETHODIMP CCUBRIDRowset::InsertRow(HCHAPTER hReserved, HACCESSOR hAccessor, void *pData, HROW *phRow)
{
	ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::InsertRow\n");

	if(phRow) *phRow = NULL;

	if(phRow)
		CHECK_CANHOLDROWS(__uuidof(IRowsetChange));

	ClearError();
	if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetChange), L"This object is in a zombie state");

	CHECK_UPDATABILITY(DBPROPVAL_UP_INSERT);

	// Determine if we're in immediate or deferred mode
	bool bDeferred = IsDeferred(this);

	// 바인딩 정보를 구함
	ATLBINDINGS *pBinding;
	{
		bool bFound = m_rgBindings.Lookup((ULONG)hAccessor, pBinding);
		if(!bFound || pBinding==NULL)
			return RaiseError(DB_E_BADACCESSORHANDLE, 0, __uuidof(IRowsetChange));
		if(!(pBinding->dwAccessorFlags & DBACCESSOR_ROWDATA))
			return RaiseError(DB_E_BADACCESSORTYPE, 0, __uuidof(IRowsetChange)); // row accessor 가 아니다.
		if(pData==NULL && pBinding->cBindings!=0)
			return RaiseError(E_INVALIDARG, 0, __uuidof(IRowsetChange));
	}

	CCUBRIDRowsetRow *pRow;
	CCUBRIDRowsetRow::KeyType key;
	{	// 새 row를 위한 Row class를 생성한다.
		DBORDINAL cCols;
		ATLCOLUMNINFO *pColInfo = GetColumnInfo(this, &cCols);
		ATLTRY(pRow = new CCUBRIDRowsetRow(m_uCodepage, -1, cCols, pColInfo, m_spConvert, m_Columns.m_defaultVal));
		if(pRow==NULL) return RaiseError(E_OUTOFMEMORY, 0, __uuidof(IRowsetChange));

		// row handle에 추가
		key = (CCUBRIDRowsetRow::KeyType)m_rgRowData.GetCount();
		if (key == 0) key++;
		
		while(m_rgRowHandles.Lookup(key)) key++;
		m_rgRowHandles.SetAt(key, pRow);

		// rowset에 데이터가 하나 늘었다.
//		m_rgRowData.SetCount(m_rgRowData.GetCount()+1);
	}

	HRESULT hrRead = pRow->ReadData(pBinding, pData, m_uCodepage);
	if(FAILED(hrRead))
	{
//		m_rgRowData.SetCount(m_rgRowData.GetCount()-1);
		m_rgRowHandles.RemoveKey(key);
		delete pRow;
		return hrRead;
	}
	pRow->m_status = DBPENDINGSTATUS_NEW;

	if(phRow)
	{	// handle을 반환할 때는 참조 카운트를 하나 증가시킨다.
		pRow->AddRefRow();
		*phRow = (HROW)key;
	}

//	m_rgBookmarks.Add(pRow->m_iRowset+1);

	if(!bDeferred)
	{	// 변화를 지금 적용
		int hConn = GetSessionPtr()->GetConnection();
		UINT uCodepage = GetSessionPtr()->GetCodepage();
		HRESULT hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName);
		if(FAILED(hr))
		{
			pRow->ReleaseRow();
			if (phRow != NULL)
				*phRow = NULL;
			return hr;
		}

		pRow->m_status = 0; // or UNCHANGED?
		if(pRow->m_dwRef==0)
		{
			m_rgRowHandles.RemoveKey(key);
			delete pRow;
		}

		DoCommit(this); // commit

		//// deferred update 모드였다가 immediate update 모드로 바뀌지는 않으므로
		//// 다른 NEW 상태의 row는 없다. 즉 m_iRowset을 변경해야 할 row는 없다.

		//// 새로 추가된 Row의 OID를 읽어들인다.
		//pRow->ReadData(GetRequestHandle(), true);
	}

	return hrRead;
}
Esempio n. 3
0
STDMETHODIMP CCUBRIDRowset::DeleteRows(HCHAPTER hReserved, DBCOUNTITEM cRows,
				const HROW rghRows[], DBROWSTATUS rgRowStatus[])
{
	ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::DeleteRows\n");

	ClearError();
	if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetChange), L"This object is in a zombie state");

	CHECK_UPDATABILITY(DBPROPVAL_UP_DELETE);

	if(cRows==0) return S_OK;
	if(rghRows==NULL && cRows>=1) return RaiseError(E_INVALIDARG, 0, __uuidof(IRowsetChange));

	// Determine if we're in immediate or deferred mode
	bool bDeferred = IsDeferred(this);

	int hConn = GetSessionPtr()->GetConnection();
	UINT uCodepage = GetSessionPtr()->GetCodepage();
	BOOL bSuccess = false;
	BOOL bFailed = false;
	for(DBCOUNTITEM i=0;i<cRows;i++)
	{
		HROW hRow = rghRows[i];

		// Attempt to locate the row in our map
		CCUBRIDRowsetRow *pRow;
		{
			bool bFound = m_rgRowHandles.Lookup((ULONG)hRow, pRow);
			if(!bFound || pRow==NULL)
			{	// invalid handle
				bFailed = true;
				if(rgRowStatus) rgRowStatus[i] = DBROWSTATUS_E_INVALID;
				continue;
			}
		}

		if(pRow->m_status==DBPENDINGSTATUS_DELETED)
		{	// already deleted
			if(rgRowStatus) rgRowStatus[i] = DBROWSTATUS_E_DELETED;
			bFailed  = true;
			continue;
		}

		ATLASSERT( pRow->m_iRowset==(ULONG)-1 || pRow->m_iRowset<m_rgRowData.GetCount() );

		DBROWSTATUS rowStat = DBROWSTATUS_S_OK;

		// mark the row as deleted
		if(pRow->m_status==DBPENDINGSTATUS_INVALIDROW)
		{
			bFailed = true;
			// unsigned high bit signified neg. number
			if(pRow->m_dwRef & 0x80000000)		
				rowStat = DBROWSTATUS_E_INVALID;
			else
				rowStat = DBROWSTATUS_E_DELETED;
		}
		else if(pRow->m_iRowset==(ULONG)-1 && pRow->m_status!=DBPENDINGSTATUS_NEW)
		{	// 새로 삽입되었고 Storage로 전송됐다.
			bFailed = true;
			rowStat = DBROWSTATUS_E_NEWLYINSERTED;
		}
		else
		{
			bSuccess = true;
			rowStat = DBROWSTATUS_S_OK;
			if(pRow->m_status==DBPENDINGSTATUS_NEW)
				MakeRowInvalid(this, pRow);
			else
				pRow->m_status = DBPENDINGSTATUS_DELETED;
		}

		if(!bDeferred && pRow->m_status==DBPENDINGSTATUS_DELETED)
		{	// 변화를 지금 적용
			// CCUBRIDRowsetRow의 delete는 ReleaseRows에서 이루어진다.
			HRESULT hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName);
			if(FAILED(hr)) return hr;

			MakeRowInvalid(this, pRow);
		}

		if(rgRowStatus) rgRowStatus[i] = rowStat;
	}

	if(!bDeferred)
		DoCommit(this); // commit

	if(bFailed)
	{
		if(bSuccess)
			return DB_S_ERRORSOCCURRED;
		else
			return RaiseError(DB_E_ERRORSOCCURRED, 0, __uuidof(IRowsetChange));
	}
	else
		return S_OK;
}
Esempio n. 4
0
STDMETHODIMP CCUBRIDRowset::SetData(HROW hRow, HACCESSOR hAccessor, void *pData)
{
	ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::SetData\n");

	ClearError();
	if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetChange), L"This object is in a zombie state");

	// cci_cursor_update를 이용하면 질의를 재실행할 때까지 SetData를 실행할 수 없다.
	// SQL and cci_execute를 이용하면 가능하다.
	CHECK_RESTART(__uuidof(IRowsetChange));

	CHECK_UPDATABILITY(DBPROPVAL_UP_CHANGE);

	// Determine if we're in immediate or deferred mode
	bool bDeferred = IsDeferred(this);

	// Attempt to locate the row in our map
	CCUBRIDRowsetRow *pRow;
	{
		bool bFound = m_rgRowHandles.Lookup((ULONG)hRow, pRow);
		if(!bFound || pRow==NULL)
			return RaiseError(DB_E_BADROWHANDLE, 0, __uuidof(IRowsetChange));
	}

	ATLASSERT( pRow->m_iRowset==(ULONG)-1 || pRow->m_iRowset<m_rgRowData.GetCount() );

	// 이미 지워진 row
	if(pRow->m_status==DBPENDINGSTATUS_DELETED || pRow->m_status==DBPENDINGSTATUS_INVALIDROW)
		return RaiseError(DB_E_DELETEDROW, 0, __uuidof(IRowsetChange));

	// 새로 삽입되었고 Storage로 전송됐다.
	if(pRow->m_iRowset==(ULONG)-1 && pRow->m_status!=DBPENDINGSTATUS_NEW)
		return DB_E_NEWLYINSERTED;

	// 바인딩 정보를 구함
	ATLBINDINGS *pBinding;
	{
		bool bFound = m_rgBindings.Lookup((ULONG)hAccessor, pBinding);
		if(!bFound || pBinding==NULL)
			return RaiseError(DB_E_BADACCESSORHANDLE, 0, __uuidof(IRowsetChange));
		if(!(pBinding->dwAccessorFlags & DBACCESSOR_ROWDATA))
			return RaiseError(DB_E_BADACCESSORTYPE, 0, __uuidof(IRowsetChange)); // row accessor 가 아니다.
		if(pData==NULL && pBinding->cBindings!=0)
			return RaiseError(E_INVALIDARG, 0, __uuidof(IRowsetChange));
	}

	HRESULT hr = pRow->ReadData(pBinding, pData, m_uCodepage);
	if(FAILED(hr)) return hr;
	// 새로 삽입된 row는 변경이 있어도 그냥 새로 삽입된 것으로 표시
	if(pRow->m_status!=DBPENDINGSTATUS_NEW)
		pRow->m_status = DBPENDINGSTATUS_CHANGED;

	if(!bDeferred)
	{	// 변화를 지금 적용
		int hConn = GetSessionPtr()->GetConnection();
		UINT uCodepage = GetSessionPtr()->GetCodepage();
		hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName);

		if (hr == DB_E_INTEGRITYVIOLATION)
			return RaiseError(DB_E_INTEGRITYVIOLATION, 0, __uuidof(IRowsetChange));

		if(FAILED(hr)) return RaiseError(DB_E_ERRORSOCCURRED, 0, __uuidof(IRowsetChange));
		
		pRow->m_status = 0; // or UNCHANGED?
		DoCommit(this); // commit
	}

	return hr; // S_OK or DB_S_ERRORSOCCURRED
}