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; }
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; }
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); } }
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; }
/** * @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() } } } }
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); }
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; }
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; }
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_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); } }