bool BL_MeshDeformer::Apply(RAS_IPolyMaterial*) { size_t i; // only apply once per frame if the mesh is actually modified if(m_pMeshObject->MeshModified() && m_lastDeformUpdate != m_gameobj->GetLastFrame()) { // For each material for(list<RAS_MeshMaterial>::iterator mit= m_pMeshObject->GetFirstMaterial(); mit != m_pMeshObject->GetLastMaterial(); ++ mit) { if(!mit->m_slots[(void*)m_gameobj]) continue; RAS_MeshSlot *slot = *mit->m_slots[(void*)m_gameobj]; RAS_MeshSlot::iterator it; // for each array for(slot->begin(it); !slot->end(it); slot->next(it)) { // For each vertex for(i=it.startvertex; i<it.endvertex; i++) { RAS_TexVert& v = it.vertex[i]; v.SetXYZ(m_bmesh->mvert[v.getOrigIndex()].co); } } } m_lastDeformUpdate = m_gameobj->GetLastFrame(); return true; } return false; }
void KX_FontObject::AddMeshUser() { m_meshUser = new RAS_TextUser(m_pClient_info); // set the part of the mesh slot that never change float *fl = GetOpenGLMatrixPtr()->getPointer(); m_meshUser->SetMatrix(fl); RAS_BucketManager *bucketManager = GetScene()->GetBucketManager(); bool created = false; RAS_MaterialBucket *bucket = bucketManager->FindBucket(GetTextMaterial(), created); // If the material bucket is just created then we add a new mesh slot. if (created) { RAS_TexVertFormat format; format.uvSize = 1; format.colorSize = 1; bucket->NewMesh(NULL, NULL, format); } /* We copy the original mesh slot which is at the begin of the list, if it's not the case it * doesn't matter as the mesh slot are all similar exepted their mesh user pointer which is * set to NULL in copy. By copying instead of adding a mesh slot we reuse the same display * array bucket. */ RAS_MeshSlot *ms = bucket->CopyMesh(*bucket->msBegin()); ms->SetMeshUser(m_meshUser); ms->SetDeformer(NULL); m_meshUser->AddMeshSlot(ms); }
RAS_Polygon* RAS_MeshObject::AddPolygon(RAS_MaterialBucket *bucket, int numverts) { RAS_MeshMaterial *mmat; RAS_Polygon *poly; RAS_MeshSlot *slot; /* find a mesh material */ mmat = GetMeshMaterial(bucket->GetPolyMaterial()); /* none found, create a new one */ if (!mmat) { RAS_MeshMaterial meshmat; meshmat.m_bucket = bucket; meshmat.m_baseslot = meshmat.m_bucket->AddMesh(numverts); meshmat.m_baseslot->m_mesh = this; m_materials.push_back(meshmat); mmat = &m_materials.back(); } /* add it to the bucket, this also adds new display arrays */ slot = mmat->m_baseslot; slot->AddPolygon(numverts); /* create a new polygon */ RAS_DisplayArray *darray = slot->CurrentDisplayArray(); poly = new RAS_Polygon(bucket, darray, numverts); m_Polygons.push_back(poly); return poly; }
void RAS_BucketManager::RenderSolidBuckets( const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools) { BucketList::iterator bit; rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED); for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) { #if 1 RAS_MaterialBucket* bucket = *bit; RAS_MeshSlot* ms; // remove the mesh slot form the list, it culls them automatically for next frame while((ms = bucket->GetNextActiveMeshSlot())) { rendertools->SetClientObject(rasty, ms->m_clientObj); while (bucket->ActivateMaterial(cameratrans, rasty, rendertools)) bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *ms); // make this mesh slot culled automatically for next frame // it will be culled out by frustrum culling ms->SetCulled(true); } #else list<RAS_MeshSlot>::iterator mit; for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { if (mit->IsCulled()) continue; rendertools->SetClientObject(rasty, mit->m_clientObj); while ((*bit)->ActivateMaterial(cameratrans, rasty, rendertools)) (*bit)->RenderMeshSlot(cameratrans, rasty, rendertools, *mit); // make this mesh slot culled automatically for next frame // it will be culled out by frustrum culling mit->SetCulled(true); } #endif } /* this code draws meshes order front-to-back instead to reduce overdraw. * it turned out slower due to much material state switching, a more clever * algorithm might do better. */ #if 0 vector<sortedmeshslot> slots; vector<sortedmeshslot>::iterator sit; OrderBuckets(cameratrans, m_SolidBuckets, slots, false); for(sit=slots.begin(); sit!=slots.end(); ++sit) { rendertools->SetClientObject(rasty, sit->m_ms->m_clientObj); while(sit->m_bucket->ActivateMaterial(cameratrans, rasty, rendertools)) sit->m_bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *(sit->m_ms)); } #endif }
RAS_MeshSlot *RAS_MaterialBucket::NewMesh(RAS_MeshObject *mesh, RAS_MeshMaterial *meshmat, const RAS_TexVertFormat& format) { RAS_MeshSlot *ms = new RAS_MeshSlot(); ms->init(this, mesh, meshmat, format); m_meshSlots.push_back(ms); return ms; }
void RAS_MeshObject::AddVertex(RAS_Polygon *poly, int i, const MT_Point3& xyz, const MT_Point2& uv, const MT_Point2& uv2, const MT_Vector4& tangent, const unsigned int rgba, const MT_Vector3& normal, bool flat, int origindex) { RAS_TexVert texvert(xyz, uv, uv2, tangent, rgba, normal, flat, origindex); RAS_MeshMaterial *mmat; RAS_DisplayArray *darray; RAS_MeshSlot *slot; int offset; mmat = GetMeshMaterial(poly->GetMaterial()->GetPolyMaterial()); slot = mmat->m_baseslot; darray = slot->CurrentDisplayArray(); { /* Shared Vertex! */ /* find vertices shared between faces, with the restriction * that they exist in the same display array, and have the * same uv coordinate etc */ vector<SharedVertex>& sharedmap = m_sharedvertex_map[origindex]; vector<SharedVertex>::iterator it; for (it = sharedmap.begin(); it != sharedmap.end(); it++) { if (it->m_darray != darray) continue; if (!it->m_darray->m_vertex[it->m_offset].closeTo(&texvert)) continue; /* found one, add it and we're done */ if (poly->IsVisible()) slot->AddPolygonVertex(it->m_offset); poly->SetVertexOffset(i, it->m_offset); return; } } /* no shared vertex found, add a new one */ offset = slot->AddVertex(texvert); if (poly->IsVisible()) slot->AddPolygonVertex(offset); poly->SetVertexOffset(i, offset); { /* Shared Vertex! */ SharedVertex shared; shared.m_darray = darray; shared.m_offset = offset; m_sharedvertex_map[origindex].push_back(shared); } }
bool KX_SoftBodyDeformer::Apply(class RAS_IPolyMaterial *polymat) { KX_BulletPhysicsController* ctrl = (KX_BulletPhysicsController*) m_gameobj->GetPhysicsController(); if (!ctrl) return false; btSoftBody* softBody= ctrl->GetSoftBody(); if (!softBody) return false; //printf("apply\n"); RAS_MeshSlot::iterator it; RAS_MeshMaterial *mmat; RAS_MeshSlot *slot; size_t i; // update the vertex in m_transverts Update(); // The vertex cache can only be updated for this deformer: // Duplicated objects with more than one ploymaterial (=multiple mesh slot per object) // share the same mesh (=the same cache). As the rendering is done per polymaterial // cycling through the objects, the entire mesh cache cannot be updated in one shot. mmat = m_pMeshObject->GetMeshMaterial(polymat); if(!mmat->m_slots[(void*)m_gameobj]) return true; slot = *mmat->m_slots[(void*)m_gameobj]; // for each array for(slot->begin(it); !slot->end(it); slot->next(it)) { btSoftBody::tNodeArray& nodes(softBody->m_nodes); int index = 0; for(i=it.startvertex; i<it.endvertex; i++,index++) { RAS_TexVert& v = it.vertex[i]; btAssert(v.getSoftBodyIndex() >= 0); MT_Point3 pt ( nodes[v.getSoftBodyIndex()].m_x.getX(), nodes[v.getSoftBodyIndex()].m_x.getY(), nodes[v.getSoftBodyIndex()].m_x.getZ()); v.SetXYZ(pt); MT_Vector3 normal ( nodes[v.getSoftBodyIndex()].m_n.getX(), nodes[v.getSoftBodyIndex()].m_n.getY(), nodes[v.getSoftBodyIndex()].m_n.getZ()); v.SetNormal(normal); } } return true; }
RAS_MeshSlot* RAS_MaterialBucket::AddMesh(int numverts) { RAS_MeshSlot *ms; m_meshSlots.push_back(RAS_MeshSlot()); ms = &m_meshSlots.back(); ms->init(this, numverts); return ms; }
void RAS_MeshObject::SetVertexColor(RAS_IPolyMaterial* mat,MT_Vector4 rgba) { RAS_MeshMaterial *mmat = GetMeshMaterial(mat); RAS_MeshSlot *slot = mmat->m_baseslot; RAS_MeshSlot::iterator it; size_t i; for (slot->begin(it); !slot->end(it); slot->next(it)) for (i=it.startvertex; i<it.endvertex; i++) it.vertex[i].SetRGBA(rgba); }
int RAS_MeshObject::NumVertices(RAS_IPolyMaterial* mat) { RAS_MeshMaterial *mmat; RAS_MeshSlot *slot; RAS_MeshSlot::iterator it; size_t len = 0; mmat = GetMeshMaterial(mat); slot = mmat->m_baseslot; for (slot->begin(it); !slot->end(it); slot->next(it)) len += it.endvertex - it.startvertex; return len; }
void RAS_MeshObject::SortPolygons(RAS_MeshSlot& ms, const MT_Transform &transform) { // Limitations: sorting is quite simple, and handles many // cases wrong, partially due to polygons being sorted per // bucket. // // a) mixed triangles/quads are sorted wrong // b) mixed materials are sorted wrong // c) more than 65k faces are sorted wrong // d) intersecting objects are sorted wrong // e) intersecting polygons are sorted wrong // // a) can be solved by making all faces either triangles or quads // if they need to be z-sorted. c) could be solved by allowing // larger buckets, b) and d) cannot be solved easily if we want // to avoid excessive state changes while drawing. e) would // require splitting polygons. RAS_MeshSlot::iterator it; size_t j; for (ms.begin(it); !ms.end(it); ms.next(it)) { unsigned int nvert = (int)it.array->m_type; unsigned int totpoly = it.totindex/nvert; if (totpoly <= 1) continue; if (it.array->m_type == RAS_DisplayArray::LINE) continue; // Extract camera Z plane... const MT_Vector3 pnorm(transform.getBasis()[2]); // unneeded: const MT_Scalar pval = transform.getOrigin()[2]; vector<polygonSlot> poly_slots(totpoly); /* get indices and z into temporary array */ for (j=0; j<totpoly; j++) poly_slots[j].get(it.vertex, it.index, j*nvert, nvert, pnorm); /* sort (stable_sort might be better, if flickering happens?) */ std::sort(poly_slots.begin(), poly_slots.end(), backtofront()); /* get indices from temporary array again */ for (j=0; j<totpoly; j++) poly_slots[j].set(it.index, j*nvert, nvert); } }
bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat) { RAS_MeshSlot::iterator it; RAS_MeshMaterial *mmat; RAS_MeshSlot *slot; size_t i, nmat, imat; // update the vertex in m_transverts if (!Update()) return false; if (m_transverts) { // the vertex cache is unique to this deformer, no need to update it // if it wasn't updated! We must update all the materials at once // because we will not get here again for the other material nmat = m_pMeshObject->NumMaterials(); for (imat=0; imat<nmat; imat++) { mmat = m_pMeshObject->GetMeshMaterial(imat); if (!mmat->m_slots[(void*)m_gameobj]) continue; slot = *mmat->m_slots[(void*)m_gameobj]; // for each array for (slot->begin(it); !slot->end(it); slot->next(it)) { // for each vertex // copy the untransformed data from the original mvert for (i=it.startvertex; i<it.endvertex; i++) { RAS_TexVert& v = it.vertex[i]; v.SetXYZ(m_transverts[v.getOrigIndex()]); if (m_copyNormals) v.SetNormal(m_transnors[v.getOrigIndex()]); } } } if (m_copyNormals) m_copyNormals = false; } return true; }
void RAS_StorageVBO::IndexPrimitives(RAS_MeshSlot& ms) { RAS_MeshSlot::iterator it; VBO *vbo; for (ms.begin(it); !ms.end(it); ms.next(it)) { vbo = m_vbo_lookup[it.array]; if (vbo == 0) m_vbo_lookup[it.array] = vbo = new VBO(it.array, it.totindex); // Update the vbo if (ms.m_mesh->MeshModified()) { vbo->UpdateData(); } vbo->Draw(*m_texco_num, m_texco, *m_attrib_num, m_attrib, m_attrib_layer); } }
void RAS_MeshObject::AddMeshUser(void *clientobj, SG_QList *head, RAS_Deformer* deformer) { list<RAS_MeshMaterial>::iterator it; list<RAS_MeshMaterial>::iterator mit; for (it = m_materials.begin();it!=m_materials.end();++it) { /* always copy from the base slot, which is never removed * since new objects can be created with the same mesh data */ if (deformer && !deformer->UseVertexArray()) { // HACK! // this deformer doesn't use vertex array => derive mesh // we must keep only the mesh slots that have unique material id // this is to match the derived mesh drawing function // Need a better solution in the future: scan the derive mesh and create vertex array RAS_IPolyMaterial* curmat = it->m_bucket->GetPolyMaterial(); if (curmat->GetFlag() & RAS_BLENDERGLSL) { for (mit = m_materials.begin(); mit != it; ++mit) { RAS_IPolyMaterial* mat = mit->m_bucket->GetPolyMaterial(); if ((mat->GetFlag() & RAS_BLENDERGLSL) && mat->GetMaterialIndex() == curmat->GetMaterialIndex()) // no need to convert current mesh slot break; } if (mit != it) continue; } } RAS_MeshSlot *ms = it->m_bucket->CopyMesh(it->m_baseslot); ms->m_clientObj = clientobj; ms->SetDeformer(deformer); it->m_slots.insert(clientobj, ms); head->QAddBack(ms); } }
RAS_TexVert* RAS_MeshObject::GetVertex(unsigned int matid, unsigned int index) { RAS_MeshMaterial *mmat; RAS_MeshSlot *slot; RAS_MeshSlot::iterator it; size_t len; mmat = GetMeshMaterial(matid); if (!mmat) return NULL; slot = mmat->m_baseslot; len = 0; for (slot->begin(it); !slot->end(it); slot->next(it)) { if (index >= len + it.endvertex - it.startvertex) len += it.endvertex - it.startvertex; else return &it.vertex[index - len]; } return NULL; }
bool KX_SoftBodyDeformer::Apply(RAS_IPolyMaterial *polymat, RAS_MeshMaterial *meshmat) { CcdPhysicsController *ctrl = (CcdPhysicsController *)m_gameobj->GetPhysicsController(); if (!ctrl) return false; btSoftBody *softBody = ctrl->GetSoftBody(); if (!softBody) return false; // update the vertex in m_transverts Update(); RAS_MeshSlot *slot = meshmat->m_slots[(void *)m_gameobj->getClientInfo()]; if (!slot) { return false; } RAS_IDisplayArray *array = slot->GetDisplayArray(); RAS_IDisplayArray *origarray = meshmat->m_baseslot->GetDisplayArray(); btSoftBody::tNodeArray& nodes(softBody->m_nodes); if (m_needUpdateAabb) { m_boundingBox->SetAabb(MT_Vector3(0.0f, 0.0f, 0.0f), MT_Vector3(0.0f, 0.0f, 0.0f)); m_needUpdateAabb = false; } // AABB Box : min/max. MT_Vector3 aabbMin; MT_Vector3 aabbMax; for (unsigned int i = 0, size = array->GetVertexCount(); i < size; ++i) { RAS_ITexVert *v = array->GetVertex(i); const RAS_TexVertInfo& vinfo = origarray->GetVertexInfo(i); /* The physics converter write the soft body index only in the original * vertex array because at this moment it doesn't know which is the * game object. It didn't cause any issues because it's always the same * vertex order. */ const unsigned int softbodyindex = vinfo.getSoftBodyIndex(); MT_Vector3 pt( nodes[softbodyindex].m_x.getX(), nodes[softbodyindex].m_x.getY(), nodes[softbodyindex].m_x.getZ()); v->SetXYZ(pt); MT_Vector3 normal( nodes[softbodyindex].m_n.getX(), nodes[softbodyindex].m_n.getY(), nodes[softbodyindex].m_n.getZ()); v->SetNormal(normal); if (!m_gameobj->GetAutoUpdateBounds()) { continue; } const MT_Vector3& scale = m_gameobj->NodeGetWorldScaling(); const MT_Vector3& invertscale = MT_Vector3(1.0f / scale.x(), 1.0f / scale.y(), 1.0f / scale.z()); const MT_Vector3& pos = m_gameobj->NodeGetWorldPosition(); const MT_Matrix3x3& rot = m_gameobj->NodeGetWorldOrientation(); // Extract object transform from the vertex position. pt = (pt - pos) * rot * invertscale; // if the AABB need an update. if (i == 0) { aabbMin = aabbMax = pt; } else { aabbMin.x() = std::min(aabbMin.x(), pt.x()); aabbMin.y() = std::min(aabbMin.y(), pt.y()); aabbMin.z() = std::min(aabbMin.z(), pt.z()); aabbMax.x() = std::max(aabbMax.x(), pt.x()); aabbMax.y() = std::max(aabbMax.y(), pt.y()); aabbMax.z() = std::max(aabbMax.z(), pt.z()); } } array->UpdateFrom(origarray, origarray->GetModifiedFlag() & (RAS_IDisplayArray::TANGENT_MODIFIED | RAS_IDisplayArray::UVS_MODIFIED | RAS_IDisplayArray::COLORS_MODIFIED)); m_boundingBox->ExtendAabb(aabbMin, aabbMax); return true; }
void RAS_StorageIM::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi) { bool obcolor = ms.m_bObjectColor; bool wireframe = m_drawingmode <= RAS_IRasterizer::KX_WIREFRAME; MT_Vector4& rgba = ms.m_RGBAcolor; RAS_MeshSlot::iterator it; if (ms.m_pDerivedMesh) { // mesh data is in derived mesh, current_bucket = ms.m_bucket; current_polymat = current_bucket->GetPolyMaterial(); current_ms = &ms; current_mesh = ms.m_mesh; current_wireframe = wireframe; // MCol *mcol = (MCol*)ms.m_pDerivedMesh->getFaceDataArray(ms.m_pDerivedMesh, CD_MCOL); /* UNUSED */ // handle two-side if (current_polymat->GetDrawingMode() & RAS_IRasterizer::KX_BACKCULL) this->SetCullFace(true); else this->SetCullFace(false); if (current_polymat->GetFlag() & RAS_BLENDERGLSL) { // GetMaterialIndex return the original mface material index, // increment by 1 to match what derived mesh is doing current_blmat_nr = current_polymat->GetMaterialIndex()+1; // For GLSL we need to retrieve the GPU material attribute Material* blmat = current_polymat->GetBlenderMaterial(); Scene* blscene = current_polymat->GetBlenderScene(); if (!wireframe && blscene && blmat) GPU_material_vertex_attributes(GPU_material_from_blender(blscene, blmat), ¤t_gpu_attribs); else memset(¤t_gpu_attribs, 0, sizeof(current_gpu_attribs)); // DM draw can mess up blending mode, restore at the end int current_blend_mode = GPU_get_material_alpha_blend(); ms.m_pDerivedMesh->drawFacesGLSL(ms.m_pDerivedMesh, CheckMaterialDM); GPU_set_material_alpha_blend(current_blend_mode); } else { //ms.m_pDerivedMesh->drawMappedFacesTex(ms.m_pDerivedMesh, CheckTexfaceDM, mcol); current_blmat_nr = current_polymat->GetMaterialIndex(); current_image = current_polymat->GetBlenderImage(); ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL, DM_DRAW_USE_ACTIVE_UV); } return; } // iterate over display arrays, each containing an index + vertex array for (ms.begin(it); !ms.end(it); ms.next(it)) { RAS_TexVert *vertex; size_t i, j, numvert; numvert = it.array->m_type; if (it.array->m_type == RAS_DisplayArray::LINE) { // line drawing glBegin(GL_LINES); for (i = 0; i < it.totindex; i += 2) { vertex = &it.vertex[it.index[i]]; glVertex3fv(vertex->getXYZ()); vertex = &it.vertex[it.index[i+1]]; glVertex3fv(vertex->getXYZ()); } glEnd(); } else { // triangle and quad drawing if (it.array->m_type == RAS_DisplayArray::TRIANGLE) glBegin(GL_TRIANGLES); else glBegin(GL_QUADS); for (i = 0; i < it.totindex; i += numvert) { if (obcolor) glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); for (j = 0; j < numvert; j++) { vertex = &it.vertex[it.index[i+j]]; if (!wireframe) { if (!obcolor) glColor4ubv((const GLubyte *)(vertex->getRGBA())); glNormal3fv(vertex->getNormal()); if (multi) TexCoord(*vertex); else glTexCoord2fv(vertex->getUV(0)); } glVertex3fv(vertex->getXYZ()); } } glEnd(); } } }
void RAS_OpenGLRasterizer::IndexPrimitives_3DText(RAS_MeshSlot& ms, class RAS_IPolyMaterial* polymat) { bool obcolor = ms.m_bObjectColor; MT_Vector4& rgba = ms.m_RGBAcolor; RAS_MeshSlot::iterator it; const STR_String& mytext = ((CValue*)m_clientobject)->GetPropertyText("Text"); // handle object color if (obcolor) { glDisableClientState(GL_COLOR_ARRAY); glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); } else glEnableClientState(GL_COLOR_ARRAY); for (ms.begin(it); !ms.end(it); ms.next(it)) { RAS_TexVert *vertex; size_t i, j, numvert; numvert = it.array->m_type; if (it.array->m_type == RAS_DisplayArray::LINE) { // line drawing, no text glBegin(GL_LINES); for (i=0; i<it.totindex; i+=2) { vertex = &it.vertex[it.index[i]]; glVertex3fv(vertex->getXYZ()); vertex = &it.vertex[it.index[i+1]]; glVertex3fv(vertex->getXYZ()); } glEnd(); } else { // triangle and quad text drawing for (i=0; i<it.totindex; i+=numvert) { float v[4][3]; int glattrib, unit; for (j=0; j<numvert; j++) { vertex = &it.vertex[it.index[i+j]]; v[j][0] = vertex->getXYZ()[0]; v[j][1] = vertex->getXYZ()[1]; v[j][2] = vertex->getXYZ()[2]; } // find the right opengl attribute glattrib = -1; if (GLEW_ARB_vertex_program) for (unit=0; unit<m_attrib_num; unit++) if (m_attrib[unit] == RAS_TEXCO_UV) glattrib = unit; GPU_render_text(polymat->GetMTFace(), polymat->GetDrawingMode(), mytext, mytext.Length(), polymat->GetMCol(), v[0], v[1], v[2], v[3], glattrib); ClearCachingInfo(); } } } glDisableClientState(GL_COLOR_ARRAY); }
void RAS_VAOpenGLRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms) { static const GLsizei stride = sizeof(RAS_TexVert); bool wireframe = m_drawingmode <= KX_WIREFRAME; RAS_MeshSlot::iterator it; GLenum drawmode; if (ms.m_pDerivedMesh) { // cannot be handled here, pass to RAS_OpenGLRasterizer RAS_OpenGLRasterizer::IndexPrimitivesInternal(ms, true); return; } if(!wireframe) EnableTextures(true); // use glDrawElements to draw each vertexarray for(ms.begin(it); !ms.end(it); ms.next(it)) { if(it.totindex == 0) continue; // drawing mode if(it.array->m_type == RAS_DisplayArray::TRIANGLE) drawmode = GL_TRIANGLES; else if(it.array->m_type == RAS_DisplayArray::QUAD) drawmode = GL_QUADS; else drawmode = GL_LINES; // colors if (drawmode != GL_LINES && !wireframe) { if (ms.m_bObjectColor) { const MT_Vector4& rgba = ms.m_RGBAcolor; glDisableClientState(GL_COLOR_ARRAY); glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); } else { glColor4f(0.0f, 0.0f, 0.0f, 1.0f); glEnableClientState(GL_COLOR_ARRAY); } } else glColor4f(0.0f, 0.0f, 0.0f, 1.0f); glVertexPointer(3, GL_FLOAT, stride, it.vertex->getXYZ()); glNormalPointer(GL_FLOAT, stride, it.vertex->getNormal()); if(!wireframe) { TexCoordPtr(it.vertex); if(glIsEnabled(GL_COLOR_ARRAY)) glColorPointer(4, GL_UNSIGNED_BYTE, stride, it.vertex->getRGBA()); } // here the actual drawing takes places glDrawElements(drawmode, it.totindex, GL_UNSIGNED_SHORT, it.index); } if(!wireframe) { glDisableClientState(GL_COLOR_ARRAY); EnableTextures(false); } }
/** * @warning This function is expensive! */ void BL_MeshDeformer::RecalcNormals() { /* We don't normalize for performance, not doing it for faces normals * gives area-weight normals which often look better anyway, and use * GL_NORMALIZE so we don't have to do per vertex normalization either * since the GPU can do it faster */ list<RAS_MeshMaterial>::iterator mit; RAS_MeshSlot::iterator it; size_t i; /* set vertex normals to zero */ memset(m_transnors, 0, sizeof(float)*3*m_bmesh->totvert); /* add face normals to vertices. */ for(mit = m_pMeshObject->GetFirstMaterial(); mit != m_pMeshObject->GetLastMaterial(); ++ mit) { if(!mit->m_slots[(void*)m_gameobj]) continue; RAS_MeshSlot *slot = *mit->m_slots[(void*)m_gameobj]; for(slot->begin(it); !slot->end(it); slot->next(it)) { int nvert = (int)it.array->m_type; for(i=0; i<it.totindex; i+=nvert) { RAS_TexVert& v1 = it.vertex[it.index[i]]; RAS_TexVert& v2 = it.vertex[it.index[i+1]]; RAS_TexVert& v3 = it.vertex[it.index[i+2]]; RAS_TexVert *v4 = NULL; const float *co1 = m_transverts[v1.getOrigIndex()]; const float *co2 = m_transverts[v2.getOrigIndex()]; const float *co3 = m_transverts[v3.getOrigIndex()]; const float *co4 = NULL; /* compute face normal */ float fnor[3], n1[3], n2[3]; if(nvert == 4) { v4 = &it.vertex[it.index[i+3]]; co4 = m_transverts[v4->getOrigIndex()]; n1[0]= co1[0]-co3[0]; n1[1]= co1[1]-co3[1]; n1[2]= co1[2]-co3[2]; n2[0]= co2[0]-co4[0]; n2[1]= co2[1]-co4[1]; n2[2]= co2[2]-co4[2]; } else { n1[0]= co1[0]-co2[0]; n2[0]= co2[0]-co3[0]; n1[1]= co1[1]-co2[1]; n2[1]= co2[1]-co3[1]; n1[2]= co1[2]-co2[2]; n2[2]= co2[2]-co3[2]; } fnor[0]= n1[1]*n2[2] - n1[2]*n2[1]; fnor[1]= n1[2]*n2[0] - n1[0]*n2[2]; fnor[2]= n1[0]*n2[1] - n1[1]*n2[0]; Normalize(fnor); /* add to vertices for smooth normals */ float *vn1 = m_transnors[v1.getOrigIndex()]; float *vn2 = m_transnors[v2.getOrigIndex()]; float *vn3 = m_transnors[v3.getOrigIndex()]; vn1[0] += fnor[0]; vn1[1] += fnor[1]; vn1[2] += fnor[2]; vn2[0] += fnor[0]; vn2[1] += fnor[1]; vn2[2] += fnor[2]; vn3[0] += fnor[0]; vn3[1] += fnor[1]; vn3[2] += fnor[2]; if(v4) { float *vn4 = m_transnors[v4->getOrigIndex()]; vn4[0] += fnor[0]; vn4[1] += fnor[1]; vn4[2] += fnor[2]; } /* in case of flat - just assign, the vertices are split */ if(v1.getFlag() & RAS_TexVert::FLAT) { v1.SetNormal(fnor); v2.SetNormal(fnor); v3.SetNormal(fnor); if(v4) v4->SetNormal(fnor); } } } } /* assign smooth vertex normals */ for(mit = m_pMeshObject->GetFirstMaterial(); mit != m_pMeshObject->GetLastMaterial(); ++ mit) { if(!mit->m_slots[(void*)m_gameobj]) continue; RAS_MeshSlot *slot = *mit->m_slots[(void*)m_gameobj]; for(slot->begin(it); !slot->end(it); slot->next(it)) { for(i=it.startvertex; i<it.endvertex; i++) { RAS_TexVert& v = it.vertex[i]; if(!(v.getFlag() & RAS_TexVert::FLAT)) v.SetNormal(m_transnors[v.getOrigIndex()]); //.safe_normalized() } } } }
PyObject *KX_MeshProxy::PyTransform(PyObject *args, PyObject *kwds) { int matindex; PyObject *pymat; bool ok = false; MT_Matrix4x4 transform; if (!PyArg_ParseTuple(args,"iO:transform", &matindex, &pymat) || !PyMatTo(pymat, transform)) { return NULL; } MT_Matrix4x4 ntransform = transform.inverse().transposed(); ntransform[0][3] = ntransform[1][3] = ntransform[2][3] = 0.0f; /* transform mesh verts */ unsigned int mit_index = 0; for (list<RAS_MeshMaterial>::iterator mit = m_meshobj->GetFirstMaterial(); (mit != m_meshobj->GetLastMaterial()); ++mit, ++mit_index) { if (matindex == -1) { /* always transform */ } else if (matindex == mit_index) { /* we found the right index! */ } else { continue; } RAS_MeshSlot *slot = mit->m_baseslot; RAS_MeshSlot::iterator it; ok = true; for (slot->begin(it); !slot->end(it); slot->next(it)) { size_t i; for (i = it.startvertex; i < it.endvertex; i++) { RAS_TexVert *vert = &it.vertex[i]; vert->Transform(transform, ntransform); } } /* if we set a material index, quit when done */ if (matindex == mit_index) { break; } } if (ok == false) { PyErr_Format(PyExc_ValueError, "mesh.transform(...): invalid material index %d", matindex); return NULL; } m_meshobj->SetMeshModified(true); Py_RETURN_NONE; }
PyObject *KX_MeshProxy::PyTransformUV(PyObject *args, PyObject *kwds) { int matindex; PyObject *pymat; int uvindex = -1; int uvindex_from = -1; bool ok = false; MT_Matrix4x4 transform; if (!PyArg_ParseTuple(args,"iO|iii:transformUV", &matindex, &pymat, &uvindex, &uvindex_from) || !PyMatTo(pymat, transform)) { return NULL; } if (uvindex < -1 || uvindex > 1) { PyErr_Format(PyExc_ValueError, "mesh.transformUV(...): invalid uv_index %d", uvindex); return NULL; } if (uvindex_from < -1 || uvindex_from > 1) { PyErr_Format(PyExc_ValueError, "mesh.transformUV(...): invalid uv_index_from %d", uvindex); return NULL; } if (uvindex_from == uvindex) { uvindex_from = -1; } /* transform mesh verts */ unsigned int mit_index = 0; for (list<RAS_MeshMaterial>::iterator mit = m_meshobj->GetFirstMaterial(); (mit != m_meshobj->GetLastMaterial()); ++mit, ++mit_index) { if (matindex == -1) { /* always transform */ } else if (matindex == mit_index) { /* we found the right index! */ } else { continue; } RAS_MeshSlot *slot = mit->m_baseslot; RAS_MeshSlot::iterator it; ok = true; for (slot->begin(it); !slot->end(it); slot->next(it)) { size_t i; for (i = it.startvertex; i < it.endvertex; i++) { RAS_TexVert *vert = &it.vertex[i]; if (uvindex_from != -1) { if (uvindex_from == 0) vert->SetUV(1, vert->getUV(0)); else vert->SetUV(0, vert->getUV(1)); } switch (uvindex) { case 0: vert->TransformUV(0, transform); break; case 1: vert->TransformUV(1, transform); break; case -1: vert->TransformUV(0, transform); vert->TransformUV(1, transform); break; } } } /* if we set a material index, quit when done */ if (matindex == mit_index) { break; } } if (ok == false) { PyErr_Format(PyExc_ValueError, "mesh.transformUV(...): invalid material index %d", matindex); return NULL; } m_meshobj->SetMeshModified(true); Py_RETURN_NONE; }