/* ================== 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 ); } } } }
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; }
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; }
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 }