void SoftwareTransform( int prim, int vertexCount, u32 vertType, u16 *&inds, int indexType, const DecVtxFormat &decVtxFormat, int &maxIndex, TransformedVertex *&drawBuffer, int &numTrans, bool &drawIndexed, const SoftwareTransformParams *params, SoftwareTransformResult *result) { u8 *decoded = params->decoded; FramebufferManagerCommon *fbman = params->fbman; TextureCacheCommon *texCache = params->texCache; TransformedVertex *transformed = params->transformed; TransformedVertex *transformedExpanded = params->transformedExpanded; float ySign = 1.0f; bool throughmode = (vertType & GE_VTYPE_THROUGH_MASK) != 0; bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled(); // TODO: Split up into multiple draw calls for GLES 2.0 where you can't guarantee support for more than 0x10000 verts. #if defined(MOBILE_DEVICE) if (vertexCount > 0x10000/3) vertexCount = 0x10000/3; #endif float uscale = 1.0f; float vscale = 1.0f; if (throughmode) { uscale /= gstate_c.curTextureWidth; vscale /= gstate_c.curTextureHeight; } bool skinningEnabled = vertTypeIsSkinningEnabled(vertType); const int w = gstate.getTextureWidth(0); const int h = gstate.getTextureHeight(0); float widthFactor = (float) w / (float) gstate_c.curTextureWidth; float heightFactor = (float) h / (float) gstate_c.curTextureHeight; Lighter lighter(vertType); float fog_end = getFloat24(gstate.fog1); float fog_slope = getFloat24(gstate.fog2); // Same fixup as in ShaderManager.cpp if (my_isinf(fog_slope)) { // not really sure what a sensible value might be. fog_slope = fog_slope < 0.0f ? -10000.0f : 10000.0f; } if (my_isnan(fog_slope)) { // Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988 // Just put the fog far away at a large finite distance. // Infinities and NaNs are rather unpredictable in shaders on many GPUs // so it's best to just make it a sane calculation. fog_end = 100000.0f; fog_slope = 1.0f; } VertexReader reader(decoded, decVtxFormat, vertType); if (throughmode) { for (int index = 0; index < maxIndex; index++) { // Do not touch the coordinates or the colors. No lighting. reader.Goto(index); // TODO: Write to a flexible buffer, we don't always need all four components. TransformedVertex &vert = transformed[index]; reader.ReadPos(vert.pos); if (reader.hasColor0()) { reader.ReadColor0_8888(vert.color0); } else { vert.color0_32 = gstate.getMaterialAmbientRGBA(); } if (reader.hasUV()) { reader.ReadUV(vert.uv); vert.u *= uscale; vert.v *= vscale; } else { vert.u = 0.0f; vert.v = 0.0f; } // Ignore color1 and fog, never used in throughmode anyway. // The w of uv is also never used (hardcoded to 1.0.) } } else { // Okay, need to actually perform the full transform. for (int index = 0; index < maxIndex; index++) { reader.Goto(index); float v[3] = {0, 0, 0}; Vec4f c0 = Vec4f(1, 1, 1, 1); Vec4f c1 = Vec4f(0, 0, 0, 0); float uv[3] = {0, 0, 1}; float fogCoef = 1.0f; // We do software T&L for now float out[3]; float pos[3]; Vec3f normal(0, 0, 1); Vec3f worldnormal(0, 0, 1); reader.ReadPos(pos); if (!skinningEnabled) { Vec3ByMatrix43(out, pos, gstate.worldMatrix); if (reader.hasNormal()) { reader.ReadNrm(normal.AsArray()); if (gstate.areNormalsReversed()) { normal = -normal; } Norm3ByMatrix43(worldnormal.AsArray(), normal.AsArray(), gstate.worldMatrix); worldnormal = worldnormal.Normalized(); } } else { float weights[8]; reader.ReadWeights(weights); if (reader.hasNormal()) reader.ReadNrm(normal.AsArray()); // Skinning Vec3f psum(0, 0, 0); Vec3f nsum(0, 0, 0); for (int i = 0; i < vertTypeGetNumBoneWeights(vertType); i++) { if (weights[i] != 0.0f) { Vec3ByMatrix43(out, pos, gstate.boneMatrix+i*12); Vec3f tpos(out); psum += tpos * weights[i]; if (reader.hasNormal()) { Vec3f norm; Norm3ByMatrix43(norm.AsArray(), normal.AsArray(), gstate.boneMatrix+i*12); nsum += norm * weights[i]; } } } // Yes, we really must multiply by the world matrix too. Vec3ByMatrix43(out, psum.AsArray(), gstate.worldMatrix); if (reader.hasNormal()) { normal = nsum; if (gstate.areNormalsReversed()) { normal = -normal; } Norm3ByMatrix43(worldnormal.AsArray(), normal.AsArray(), gstate.worldMatrix); worldnormal = worldnormal.Normalized(); } } // Perform lighting here if enabled. don't need to check through, it's checked above. Vec4f unlitColor = Vec4f(1, 1, 1, 1); if (reader.hasColor0()) { reader.ReadColor0(&unlitColor.x); } else { unlitColor = Vec4f::FromRGBA(gstate.getMaterialAmbientRGBA()); } if (gstate.isLightingEnabled()) { float litColor0[4]; float litColor1[4]; lighter.Light(litColor0, litColor1, unlitColor.AsArray(), out, worldnormal); // Don't ignore gstate.lmode - we should send two colors in that case for (int j = 0; j < 4; j++) { c0[j] = litColor0[j]; } if (lmode) { // Separate colors for (int j = 0; j < 4; j++) { c1[j] = litColor1[j]; } } else { // Summed color into c0 (will clamp in ToRGBA().) for (int j = 0; j < 4; j++) { c0[j] += litColor1[j]; } } } else { if (reader.hasColor0()) { for (int j = 0; j < 4; j++) { c0[j] = unlitColor[j]; } } else { c0 = Vec4f::FromRGBA(gstate.getMaterialAmbientRGBA()); } if (lmode) { // c1 is already 0. } } float ruv[2] = {0.0f, 0.0f}; if (reader.hasUV()) reader.ReadUV(ruv); // Perform texture coordinate generation after the transform and lighting - one style of UV depends on lights. switch (gstate.getUVGenMode()) { case GE_TEXMAP_TEXTURE_COORDS: // UV mapping case GE_TEXMAP_UNKNOWN: // Seen in Riviera. Unsure of meaning, but this works. // We always prescale in the vertex decoder now. uv[0] = ruv[0]; uv[1] = ruv[1]; uv[2] = 1.0f; break; case GE_TEXMAP_TEXTURE_MATRIX: { // Projection mapping Vec3f source; switch (gstate.getUVProjMode()) { case GE_PROJMAP_POSITION: // Use model space XYZ as source source = pos; break; case GE_PROJMAP_UV: // Use unscaled UV as source source = Vec3f(ruv[0], ruv[1], 0.0f); break; case GE_PROJMAP_NORMALIZED_NORMAL: // Use normalized normal as source source = normal.Normalized(); if (!reader.hasNormal()) { ERROR_LOG_REPORT(G3D, "Normal projection mapping without normal?"); } break; case GE_PROJMAP_NORMAL: // Use non-normalized normal as source! source = normal; if (!reader.hasNormal()) { ERROR_LOG_REPORT(G3D, "Normal projection mapping without normal?"); } break; } float uvw[3]; Vec3ByMatrix43(uvw, &source.x, gstate.tgenMatrix); uv[0] = uvw[0]; uv[1] = uvw[1]; uv[2] = uvw[2]; } break; case GE_TEXMAP_ENVIRONMENT_MAP: // Shade mapping - use two light sources to generate U and V. { Vec3f lightpos0 = Vec3f(&lighter.lpos[gstate.getUVLS0() * 3]).Normalized(); Vec3f lightpos1 = Vec3f(&lighter.lpos[gstate.getUVLS1() * 3]).Normalized(); uv[0] = (1.0f + Dot(lightpos0, worldnormal))/2.0f; uv[1] = (1.0f + Dot(lightpos1, worldnormal))/2.0f; uv[2] = 1.0f; } break; default: // Illegal ERROR_LOG_REPORT(G3D, "Impossible UV gen mode? %d", gstate.getUVGenMode()); break; } uv[0] = uv[0] * widthFactor; uv[1] = uv[1] * heightFactor; // Transform the coord by the view matrix. Vec3ByMatrix43(v, out, gstate.viewMatrix); fogCoef = (v[2] + fog_end) * fog_slope; // TODO: Write to a flexible buffer, we don't always need all four components. memcpy(&transformed[index].x, v, 3 * sizeof(float)); transformed[index].fog = fogCoef; memcpy(&transformed[index].u, uv, 3 * sizeof(float)); transformed[index].color0_32 = c0.ToRGBA(); transformed[index].color1_32 = c1.ToRGBA(); // The multiplication by the projection matrix is still performed in the vertex shader. // So is vertex depth rounding, to simulate the 16-bit depth buffer. } } // Here's the best opportunity to try to detect rectangles used to clear the screen, and // replace them with real clears. This can provide a speedup on certain mobile chips. // // An alternative option is to simply ditch all the verts except the first and last to create a single // rectangle out of many. Quite a small optimization though. // Experiment: Disable on PowerVR (see issue #6290) // TODO: This bleeds outside the play area in non-buffered mode. Big deal? Probably not. bool reallyAClear = false; if (maxIndex > 1 && prim == GE_PRIM_RECTANGLES && gstate.isModeClear()) { int scissorX2 = gstate.getScissorX2() + 1; int scissorY2 = gstate.getScissorY2() + 1; reallyAClear = IsReallyAClear(transformed, maxIndex, scissorX2, scissorY2); } if (reallyAClear && gl_extensions.gpuVendor != GPU_VENDOR_POWERVR) { // && g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) { // If alpha is not allowed to be separate, it must match for both depth/stencil and color. Vulkan requires this. bool alphaMatchesColor = gstate.isClearModeColorMask() == gstate.isClearModeAlphaMask(); bool depthMatchesStencil = gstate.isClearModeAlphaMask() == gstate.isClearModeDepthMask(); if (params->allowSeparateAlphaClear || (alphaMatchesColor && depthMatchesStencil)) { result->color = transformed[1].color0_32; // Need to rescale from a [0, 1] float. This is the final transformed value. result->depth = ToScaledDepth((s16)(int)(transformed[1].z * 65535.0f)); result->action = SW_CLEAR; return; } } // This means we're using a framebuffer (and one that isn't big enough.) if (gstate_c.curTextureHeight < (u32)h && maxIndex >= 2) { // Even if not rectangles, this will detect if either of the first two are outside the framebuffer. // HACK: Adding one pixel margin to this detection fixes issues in Assassin's Creed : Bloodlines, // while still keeping BOF working (see below). const float invTexH = 1.0f / gstate_c.curTextureHeight; // size of one texel. bool tlOutside; bool tlAlmostOutside; bool brOutside; // If we're outside heightFactor, then v must be wrapping or clamping. Avoid this workaround. // If we're <= 1.0f, we're inside the framebuffer (workaround not needed.) // We buffer that 1.0f a little more with a texel to avoid some false positives. tlOutside = transformed[0].v <= heightFactor && transformed[0].v > 1.0f + invTexH; brOutside = transformed[1].v <= heightFactor && transformed[1].v > 1.0f + invTexH; // Careful: if br is outside, but tl is well inside, this workaround still doesn't make sense. // We go with halfway, since we overestimate framebuffer heights sometimes but not by much. tlAlmostOutside = transformed[0].v <= heightFactor && transformed[0].v >= 0.5f; if (tlOutside || (brOutside && tlAlmostOutside)) { // Okay, so we're texturing from outside the framebuffer, but inside the texture height. // Breath of Fire 3 does this to access a render surface at an offset. const u32 bpp = fbman->GetTargetFormat() == GE_FORMAT_8888 ? 4 : 2; const u32 prevH = texCache->AttachedDrawingHeight(); const u32 fb_size = bpp * fbman->GetTargetStride() * prevH; const u32 prevYOffset = gstate_c.curTextureYOffset; if (texCache->SetOffsetTexture(fb_size)) { const float oldWidthFactor = widthFactor; const float oldHeightFactor = heightFactor; widthFactor = (float) w / (float) gstate_c.curTextureWidth; heightFactor = (float) h / (float) gstate_c.curTextureHeight; // We've already baked in the old gstate_c.curTextureYOffset, so correct. const float yDiff = (float) (prevH + prevYOffset - gstate_c.curTextureYOffset) / (float) h; for (int index = 0; index < maxIndex; ++index) { transformed[index].u *= widthFactor / oldWidthFactor; // Inverse it back to scale to the new FBO, and add 1.0f to account for old FBO. transformed[index].v = (transformed[index].v / oldHeightFactor - yDiff) * heightFactor; } } } } // Step 2: expand rectangles. drawBuffer = transformed; numTrans = 0; drawIndexed = false; if (prim != GE_PRIM_RECTANGLES) { // We can simply draw the unexpanded buffer. numTrans = vertexCount; drawIndexed = true; } else { bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; if (useBufferedRendering) ySign = -ySign; float flippedMatrix[16]; if (!throughmode) { memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float)); const bool invertedY = useBufferedRendering ? (gstate_c.vpHeight < 0) : (gstate_c.vpHeight > 0); if (invertedY) { flippedMatrix[1] = -flippedMatrix[1]; flippedMatrix[5] = -flippedMatrix[5]; flippedMatrix[9] = -flippedMatrix[9]; flippedMatrix[13] = -flippedMatrix[13]; } const bool invertedX = gstate_c.vpWidth < 0; if (invertedX) { flippedMatrix[0] = -flippedMatrix[0]; flippedMatrix[4] = -flippedMatrix[4]; flippedMatrix[8] = -flippedMatrix[8]; flippedMatrix[12] = -flippedMatrix[12]; } } //rectangles always need 2 vertices, disregard the last one if there's an odd number vertexCount = vertexCount & ~1; numTrans = 0; drawBuffer = transformedExpanded; TransformedVertex *trans = &transformedExpanded[0]; const u16 *indsIn = (const u16 *)inds; u16 *newInds = inds + vertexCount; u16 *indsOut = newInds; maxIndex = 4 * vertexCount; for (int i = 0; i < vertexCount; i += 2) { const TransformedVertex &transVtxTL = transformed[indsIn[i + 0]]; const TransformedVertex &transVtxBR = transformed[indsIn[i + 1]]; // We have to turn the rectangle into two triangles, so 6 points. // This is 4 verts + 6 indices. // bottom right trans[0] = transVtxBR; // top right trans[1] = transVtxBR; trans[1].y = transVtxTL.y; trans[1].v = transVtxTL.v; // top left trans[2] = transVtxBR; trans[2].x = transVtxTL.x; trans[2].y = transVtxTL.y; trans[2].u = transVtxTL.u; trans[2].v = transVtxTL.v; // bottom left trans[3] = transVtxBR; trans[3].x = transVtxTL.x; trans[3].u = transVtxTL.u; // That's the four corners. Now process UV rotation. if (throughmode) RotateUVThrough(trans); else RotateUV(trans, flippedMatrix, ySign); // Triangle: BR-TR-TL indsOut[0] = i * 2 + 0; indsOut[1] = i * 2 + 1; indsOut[2] = i * 2 + 2; // Triangle: BL-BR-TL indsOut[3] = i * 2 + 3; indsOut[4] = i * 2 + 0; indsOut[5] = i * 2 + 2; trans += 4; indsOut += 6; numTrans += 6; } inds = newInds; drawIndexed = true; // We don't know the color until here, so we have to do it now, instead of in StateMapping. // Might want to reconsider the order of things later... if (gstate.isModeClear() && gstate.isClearModeAlphaMask()) { result->setStencil = true; if (vertexCount > 1) { // Take the bottom right alpha value of the first rect as the stencil value. // Technically, each rect could individually fill its stencil, but most of the // time they use the same one. result->stencilValue = transformed[indsIn[1]].color0[3]; } else { result->stencilValue = 0; } } } result->action = SW_DRAW_PRIMITIVES; }
BlenderMeshExample(int argc, const char* argv[]) : prog() , camera_matrix(prog, "CameraMatrix") , light_position(prog, "LightPosition") , camera_position(prog, "CameraPosition") , face_normals(prog, "FaceNormals") , element_count(0) { using namespace oglplus; VertexShader vs; vs.Source( "#version 330\n" "uniform mat4 CameraMatrix, ProjectionMatrix;" "uniform vec3 LightPosition, CameraPosition;" "mat4 Matrix = ProjectionMatrix * CameraMatrix;" "in vec3 Position;" "in vec3 Normal;" "out vec3 vertNormal;" "out vec3 vertLightDir;" "out vec3 vertViewDir;" "void main(void)" "{" " vertNormal = Normal;" " vertLightDir = LightPosition - Position;" " vertViewDir = CameraPosition - Position;" " gl_Position = Matrix * vec4(Position, 1.0);" "}" ); vs.Compile(); prog.AttachShader(vs); GeometryShader gs; gs.Source( "#version 330\n" "layout (triangles) in;" "layout (triangle_strip, max_vertices=3) out;" "uniform bool FaceNormals;" "in vec3 vertNormal[3];" "in vec3 vertLightDir[3];" "in vec3 vertViewDir[3];" "out vec3 geomNormal;" "out vec3 geomLightDir;" "out vec3 geomViewDir;" "void main(void)" "{" " vec3 fn;" " if(FaceNormals)" " {" " vec3 p0 = gl_in[0].gl_Position.xyz;" " vec3 p1 = gl_in[1].gl_Position.xyz;" " vec3 p2 = gl_in[2].gl_Position.xyz;" " fn = normalize(cross(p1-p0, p2-p0));" " }" " for(int v=0; v!=3; ++v)" " {" " gl_Position = gl_in[v].gl_Position;" " if(FaceNormals) geomNormal = fn;" " else geomNormal = vertNormal[v];" " geomLightDir = vertLightDir[v];" " geomViewDir = vertViewDir[v];" " EmitVertex();" " }" " EndPrimitive();" "}" ); gs.Compile(); prog.AttachShader(gs); FragmentShader fs; fs.Source( "#version 330\n" "in vec3 geomNormal;" "in vec3 geomLightDir;" "in vec3 geomViewDir;" "out vec3 fragColor;" "void main(void)" "{" " vec3 LightColor = vec3(1.0, 1.0, 1.0);" " vec3 MatColor = vec3(0.5, 0.5, 0.5);" " vec3 LightRefl = reflect(-geomLightDir, geomNormal);" " float Ambient = 0.3;" " float Diffuse = max(dot(" " normalize(geomNormal)," " normalize(geomLightDir)" " ), 0.0);" " float Contour = pow((1.0 - max(dot(" " normalize(geomNormal)," " normalize(geomViewDir)" " )-0.1, 0.0))*1.05, 4.0);" " float Specular = pow(clamp(dot(" " normalize(geomViewDir)," " normalize(LightRefl)" " )+0.005, 0.0, 0.98), 64.0);" " fragColor = MatColor * LightColor * (Contour + Diffuse + Ambient)+" " LightColor * Specular;" "}" ); fs.Compile(); prog.AttachShader(fs); prog.Link(); prog.Use(); gl.PrimitiveRestartIndex(0); // vectors with vertex position and normals // the values at index 0 is unused // 0 is used as primitive restart index std::vector<GLfloat> pos_data(3, 0.0); std::vector<GLfloat> nml_data(3, 0.0); // index offset starting at 1 GLuint index_offset = 1; // vectors with vertex indices std::vector<GLuint> idx_data(1, 0); // open an input stream std::ifstream input(argc>1? argv[1]: "./test.blend"); // check if we succeeded if(!input.good()) throw std::runtime_error("Error opening file for reading"); // parse the input stream imports::BlendFile blend_file(input); // get the file's global block auto glob_block = blend_file.StructuredGlobalBlock(); // get the default scene auto scene_data = blend_file[glob_block.curscene]; // // get the pointer to the first object in the scene auto object_link_ptr = scene_data.Field<void*>("base.first").Get(); // and go through the whole list of objects while(object_link_ptr) { // for each list element open the linked list block auto object_link_data = blend_file[object_link_ptr]; // get the pointer to its object auto object_ptr = object_link_data.Field<void*>("object").Get(); // open the object block (if any) if(object_ptr) try { auto object_data = blend_file[object_ptr]; // get the data pointer auto object_data_ptr = object_data.Field<void*>("data").Get(); // open the data block (if any) if(object_data_ptr) { auto object_data_data = blend_file[object_data_ptr]; // if it is a mesh if(object_data_data.StructureName() == "Mesh") { // get the object matrix field auto object_obmat_field = object_data.Field<float>("obmat"); // make a transformation matrix Mat4f obmat( object_obmat_field.Get(0, 0), object_obmat_field.Get(0, 4), object_obmat_field.Get(0, 8), object_obmat_field.Get(0,12), object_obmat_field.Get(0, 1), object_obmat_field.Get(0, 5), object_obmat_field.Get(0, 9), object_obmat_field.Get(0,13), object_obmat_field.Get(0, 2), object_obmat_field.Get(0, 6), object_obmat_field.Get(0,10), object_obmat_field.Get(0,14), object_obmat_field.Get(0, 3), object_obmat_field.Get(0, 7), object_obmat_field.Get(0,11), object_obmat_field.Get(0,15) ); // the number of vertices std::size_t n_verts = 0; // get the vertex block pointer auto vertex_ptr = object_data_data.Field<void*>("mvert").Get(); // open the vertex block (if any) if(vertex_ptr) { auto vertex_data = blend_file[vertex_ptr]; // get the number of vertices in the block n_verts = vertex_data.BlockElementCount(); // get the vertex coordinate and normal fields auto vertex_co_field = vertex_data.Field<float>("co"); auto vertex_no_field = vertex_data.Field<short>("no"); // make two vectors of position and normal data std::vector<GLfloat> ps(3 * n_verts); std::vector<GLfloat> ns(3 * n_verts); for(std::size_t v=0; v!=n_verts; ++v) { // (transpose y and z axes) // get the positional coordinates Vec4f position( vertex_co_field.Get(v, 0), vertex_co_field.Get(v, 1), vertex_co_field.Get(v, 2), 1.0f ); Vec4f newpos = obmat * position; ps[3*v+0] = newpos.x(); ps[3*v+1] = newpos.z(); ps[3*v+2] =-newpos.y(); // get the normals Vec4f normal( vertex_no_field.Get(v, 0), vertex_no_field.Get(v, 1), vertex_no_field.Get(v, 2), 0.0f ); Vec4f newnorm = obmat * normal; ns[3*v+0] = newnorm.x(); ns[3*v+1] = newnorm.z(); ns[3*v+2] =-newnorm.y(); } // append the values pos_data.insert(pos_data.end(), ps.begin(), ps.end()); nml_data.insert(nml_data.end(), ns.begin(), ns.end()); } // get the face block pointer auto face_ptr = object_data_data.Field<void*>("mface").Get(); // open the face block (if any) if(face_ptr) { auto face_data = blend_file[face_ptr]; // get the number of faces in the block std::size_t n_faces = face_data.BlockElementCount(); // get the vertex index fields of the face auto face_v1_field = face_data.Field<int>("v1"); auto face_v2_field = face_data.Field<int>("v2"); auto face_v3_field = face_data.Field<int>("v3"); auto face_v4_field = face_data.Field<int>("v4"); // make a vector of index data std::vector<GLuint> is(5 * n_faces); for(std::size_t f=0; f!=n_faces; ++f) { // get face vertex indices int v1 = face_v1_field.Get(f); int v2 = face_v2_field.Get(f); int v3 = face_v3_field.Get(f); int v4 = face_v4_field.Get(f); is[5*f+0] = v1+index_offset; is[5*f+1] = v2+index_offset; is[5*f+2] = v3+index_offset; is[5*f+3] = v4?v4+index_offset:0; is[5*f+4] = 0; // primitive restart index } // append the values idx_data.insert(idx_data.end(), is.begin(), is.end()); } // get the poly block pointer auto poly_ptr = object_data_data.TryGet<void*>("mpoly", nullptr); // and the loop block pointer auto loop_ptr = object_data_data.TryGet<void*>("mloop", nullptr); // open the poly and loop blocks (if we have both) if(poly_ptr && loop_ptr) { auto poly_data = blend_file[poly_ptr]; auto loop_data = blend_file[loop_ptr]; // get the number of polys in the block std::size_t n_polys = poly_data.BlockElementCount(); // get the fields of poly and loop auto poly_loopstart_field = poly_data.Field<int>("loopstart"); auto poly_totloop_field = poly_data.Field<int>("totloop"); auto loop_v_field = loop_data.Field<int>("v"); // make a vector of index data std::vector<GLuint> is; for(std::size_t f=0; f!=n_polys; ++f) { int ls = poly_loopstart_field.Get(f); int tl = poly_totloop_field.Get(f); for(int l=0; l!=tl; ++l) { int v = loop_v_field.Get(ls+l); is.push_back(v+index_offset); } is.push_back(0); // primitive restart index } // append the values idx_data.insert(idx_data.end(), is.begin(), is.end()); } index_offset += n_verts; } } } catch(...) { } // and get the pointer to the nex block object_link_ptr = object_link_data.Field<void*>("next").Get(); } meshes.Bind(); positions.Bind(Buffer::Target::Array); { Buffer::Data(Buffer::Target::Array, pos_data); VertexAttribArray attr(prog, "Position"); attr.Setup<GLfloat>(3); attr.Enable(); } normals.Bind(Buffer::Target::Array); { Buffer::Data(Buffer::Target::Array, nml_data); VertexAttribArray attr(prog, "Normal"); attr.Setup<GLfloat>(3); attr.Enable(); } indices.Bind(Buffer::Target::ElementArray); Buffer::Data(Buffer::Target::ElementArray, idx_data); element_count = idx_data.size(); // find the extremes of the mesh(es) GLfloat min_x = pos_data[3], max_x = pos_data[3]; GLfloat min_y = pos_data[4], max_y = pos_data[4]; GLfloat min_z = pos_data[5], max_z = pos_data[5]; for(std::size_t v=1, vn=pos_data.size()/3; v!=vn; ++v) { GLfloat x = pos_data[v*3+0]; GLfloat y = pos_data[v*3+1]; GLfloat z = pos_data[v*3+2]; if(min_x > x) min_x = x; if(min_y > y) min_y = y; if(min_z > z) min_z = z; if(max_x < x) max_x = x; if(max_y < y) max_y = y; if(max_z < z) max_z = z; } // position the camera target camera_target = Vec3f( (min_x + max_x) * 0.5, (min_y + max_y) * 0.5, (min_z + max_z) * 0.5 ); // and calculate a good value for camera distance camera_distance = 1.1*Distance(camera_target, Vec3f(min_x, min_y, min_z))+1.0; gl.ClearColor(0.17f, 0.22f, 0.17f, 0.0f); gl.ClearDepth(1.0f); gl.Enable(Capability::DepthTest); gl.Enable(Capability::PrimitiveRestart); }
void CollisionOutline_Impl::calculate_penetration_depth( std::vector< CollidingContours > & collision_info ) { // Figure out the pen-depth for(std::vector<CollidingContours>::iterator it = collision_info.begin(); it != collision_info.end(); ++it) { CollidingContours &cc = (*it); if(cc.points.size() % 2 != 0) { std::cout << "ERROR: we have an uneven number of collisionpoints: " << cc.points.size() << "\n"; for(std::vector<CollisionPoint>::iterator pit = cc.points.begin(); pit != cc.points.end(); ++pit) { CollisionPoint &p1 = (*pit); std::cout << "\tLineSegment1:" << "(" << cc.contour1->get_points()[p1.contour1_line_start].x << "," << cc.contour1->get_points()[p1.contour1_line_start].y << ") - " << "(" << cc.contour1->get_points()[p1.contour1_line_end].x << "," << cc.contour1->get_points()[p1.contour1_line_end].y << ")\n"; std::cout << "\tLineSegment2:" << "(" << cc.contour2->get_points()[p1.contour2_line_start].x << "," << cc.contour2->get_points()[p1.contour2_line_start].y << ") - " << "(" << cc.contour2->get_points()[p1.contour2_line_end].x << "," << cc.contour2->get_points()[p1.contour2_line_end].y << ")\n"; std::cout << "\tColPoint: ("<<p1.point.x<<","<<p1.point.y<<")\n"; std::cout << "\tColNormal: ("<<p1.normal.x<<","<<p1.normal.y<<")\n"; std::cout << "\tis_entry: " << p1.is_entry <<"\n"; std::cout << "\tcontour1_line_start: "<<p1.contour1_line_start<<", " <<"contour1_line_end: "<<p1.contour1_line_end<<",\n" <<"\tcontour2_line_start: "<<p1.contour2_line_start<<", " <<"contour2_line_end: "<<p1.contour2_line_end <<"\n"; } std::cout << "RORRE\n"; continue; } // First calculate one common normal for the whole thing // FIXME: oposing normals might generate (0,0) as normal, and that can not be right. Vec4f normal; unsigned int cp; for(cp = 0; cp < cc.points.size(); cp+=2) { std::vector<Pointf> c1points; std::vector<Pointf> c2points; int firstpoint = cp; if(!cc.points[firstpoint].is_entry) firstpoint++; CollisionPoint p1 = cc.points[firstpoint % cc.points.size()]; CollisionPoint p2 = cc.points[(firstpoint+1) % cc.points.size()]; normal.x += -(p1.point - p2.point).y; normal.y += (p1.point - p2.point).x; } normal.normalize3(); cc.penetration_normal = Pointf(normal.x, normal.y); // Now look at each and every overlapping region cc.penetration_depth = 0.0; for(unsigned int cp2 = 0; cp2 < cc.points.size(); cp2+=2) { std::vector<Pointf> c1points; std::vector<Pointf> c2points; int firstpoint = cp2; if(!cc.points[firstpoint].is_entry) firstpoint++; CollisionPoint p1 = cc.points[firstpoint % cc.points.size()]; CollisionPoint p2 = cc.points[(firstpoint+1) % cc.points.size()]; // Get points inside on c1 c1points.push_back(p2.point - p1.point); c1points.push_back(p1.point - p1.point); for(int p4 = p1.contour1_line_end; p4 != p2.contour1_line_end; p4 = ((p4+1) % cc.contour1->get_points().size())) { c1points.push_back(cc.contour1->get_points()[p4] - p1.point); //c1points.push_back(cc.contour1->points[p]); } // Get points inside on c2 c2points.push_back(p2.point - p1.point); c2points.push_back(p1.point - p1.point); for(int p6 = p2.contour2_line_end; p6 != p1.contour2_line_end; p6 = ((p6+1) % cc.contour2->get_points().size())) { c2points.push_back(cc.contour2->get_points()[p6] - p1.point); //c2points.push_back(cc.contour2->points[p]); } // Calculate the penetration-depth of this overlap float c1maxdepth = FLT_MAX; float c2maxdepth = FLT_MIN; for(unsigned int p5 = 0; p5 < c1points.size(); p5++) { // The dotproduct is the projection onto an other vector float newdepth = c1points[p5].x * normal.x + c1points[p5].y * normal.y; if(newdepth < c1maxdepth) { cc.contour1_deep_point = c1points[p5] + p1.point; c1maxdepth = newdepth; } } for(unsigned int p = 0; p < c2points.size(); p++) { // The dotproduct is the projection onto an other vector float newdepth = c2points[p].x * normal.x + c2points[p].y * normal.y; if(newdepth > c2maxdepth) { cc.contour2_deep_point = c2points[p] + p1.point; c2maxdepth = newdepth; } } cc.penetration_depth = max(cc.penetration_depth, c2maxdepth - c1maxdepth); } //NONO: maxpendepth = std::min(maxpendepth, 40.0f); } }
SmartTextureObjectData createPyramidNormalMap( const math::Vec2ui& size , const math::Vec2ui& pyramidTiles , float pyramidHeight ) //Depth of a pyramid in texel space { SmartTextureObjectData texture = new TextureObjectData; unsigned int texWidth = size[0]; unsigned int texHeight = size[1]; texture->m_size = size; texture->m_data.resize(size[0] * size[1]); //Texel lengths in texture space Vec2f incr( 1.0f / texWidth, 1.0f / texHeight ); //Dimensions of one pyramid unsigned int pyramidIX = texWidth / pyramidTiles[0]; unsigned int pyramidIY = texHeight / pyramidTiles[1]; //Calculate all four occurring normals of the pyramid ahead of time Vec4f wNormalLeft = Vec4f( -pyramidHeight, 0.0f, 0.5f * incr[0] * pyramidIX, 0.0f); Vec4f wNormalRight = Vec4f( pyramidHeight, 0.0f, 0.5f * incr[0] * pyramidIX, 0.0f); Vec4f wNormalTop = Vec4f( 0.0f, pyramidHeight, 0.5f * incr[1] * pyramidIY, 0.0f); Vec4f wNormalBottom = Vec4f( 0.0f, -pyramidHeight, 0.5f * incr[1] * pyramidIY, 0.0f); //Normalize our normals wNormalLeft.normalize(); wNormalRight.normalize(); wNormalTop.normalize(); wNormalBottom.normalize(); //Clamp our normals to [0, 1] wNormalLeft = 0.5f*wNormalLeft + Vec4f(0.5f, 0.5f, 0.5f, 0.0f); wNormalRight = 0.5f*wNormalRight + Vec4f(0.5f, 0.5f, 0.5f, 0.0f); wNormalTop = 0.5f*wNormalTop + Vec4f(0.5f, 0.5f, 0.5f, 0.0f); wNormalBottom = 0.5f*wNormalBottom + Vec4f(0.5f, 0.5f, 0.5f, 0.0f); for(unsigned int iy = 0; iy < texHeight; iy++) { //Get our vertical texel position relative to the center of the current pyramid tile int iyrel = iy % pyramidIY - pyramidIY / 2; for(unsigned int ix = 0; ix < texWidth; ix++) { //Get our horizontal texel position relative to the center of the current pyramid tile int ixrel = ix % pyramidIX - pyramidIX / 2; unsigned int curTexel = iy * texWidth + ix; //Assign the appropriate normal according to what face of the pyramid we're on if( iyrel > abs(ixrel) ) { texture->m_data[curTexel] = wNormalTop; } else if( iyrel > ixrel ) { texture->m_data[curTexel] = wNormalLeft; } else if( iyrel > -ixrel ) { texture->m_data[curTexel] = wNormalRight; } else { texture->m_data[curTexel] = wNormalBottom; } } } return texture; }
void ShaderProgramGl::setUniform(const string &name, const Vec4f &value){ assertGl(); glUniform4fvARB(getLocation(name), 1, value.ptr()); assertGl(); }
inline float PlaneDistance(Vec4f plane, Vec3f p) { return dot(plane.AsVec3(), p) + plane[3]; }
ref_ptr<Group> VBSPGeometry::createGeometry() { ref_ptr<Group> rootGroup; ref_ptr<Geode> geode; ref_ptr<Geometry> geometry; Vec4f color; ref_ptr<Vec4Array> colorArray; // Create the root group (we'll attach everything to this group and // return it) rootGroup = new Group(); // Create a geode for the geometries geode = new Geode(); rootGroup->addChild(geode.get()); // See if there are any regular (non-displaced) faces to render if (primitive_set->size() > 0) { // Create a geometry object for the regular surfaces geometry = new Geometry(); // Add the vertex attributes geometry->setVertexArray(vertex_array.get()); geometry->setNormalArray(normal_array.get(), Array::BIND_PER_VERTEX); geometry->setTexCoordArray(0, texcoord_array.get()); // Add an overall color color.set(1.0, 1.0, 1.0, 1.0); colorArray = new Vec4Array(1, &color); geometry->setColorArray(colorArray.get(), Array::BIND_OVERALL); // Add our primitive set to the geometry geometry->addPrimitiveSet(primitive_set.get()); // Add the geometry to the geode geode->addDrawable(geometry.get()); // Now, stripify the geode to convert the POLYGON primitives to // triangle strips osgUtil::TriStripVisitor tsv; geode->accept(tsv); tsv.stripify(); } // Now do the same for the displacement surfaces (if any) if (disp_primitive_set->size() > 0) { // Create a geometry object for the regular surfaces geometry = new Geometry(); // Add the vertex attributes geometry->setVertexArray(disp_vertex_array.get()); geometry->setNormalArray(disp_normal_array.get(), Array::BIND_PER_VERTEX); geometry->setColorArray(disp_vertex_attr_array.get(), Array::BIND_PER_VERTEX); geometry->setTexCoordArray(0, disp_texcoord_array.get()); geometry->setTexCoordArray(1, disp_texcoord_array.get()); // Add our primitive set to the geometry geometry->addPrimitiveSet(disp_primitive_set.get()); // Add the geometry to the geode geode->addDrawable(geometry.get()); } // Return the root group return rootGroup; }
void Shader::uniformF(const std::string &name, const Vec4f &v) { glf->glUniform4f(uniform(name), v.x(), v.y(), v.z(), v.w()); }
static inline void changeGenFunc( GLenum oldfunc, Node *oldbeacon, GLenum coord, GLenum gen, GLenum func, const Vec4f &plane, Node *beacon, Matrix &cameraMat, UInt32 eyeMode, Matrix &eyeMatrix) { #if !defined(OSG_OGL_COREONLY) || defined(OSG_CHECK_COREONLY) if(beacon != NULL) { Matrix beaconMat; beacon->getToWorld(beaconMat); beaconMat.multLeft(cameraMat); glPushMatrix(); glLoadMatrixf(beaconMat.getValues()); glTexGenfv(coord, GL_EYE_PLANE, const_cast<GLfloat *>(plane.getValues())); glTexGeni(coord, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glPopMatrix(); if(oldfunc == GL_NONE && oldbeacon == NULL) glEnable(gen); } else if(func == GL_EYE_LINEAR) { glPushMatrix(); switch(eyeMode) { case TexGenChunk::EyeModelViewIdentity: glLoadIdentity(); break; case TexGenChunk::EyeModelViewStored: glLoadMatrixf(eyeMatrix.getValues()); break; case TexGenChunk::EyeModelViewCamera: glLoadMatrixf(cameraMat.getValues()); break; default: break; } glTexGenfv(coord, GL_EYE_PLANE, const_cast<GLfloat *>(plane.getValues())); glTexGeni(coord, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glPopMatrix(); if(oldfunc == GL_NONE && oldbeacon == NULL) glEnable(gen); } else if(func != GL_NONE) { glTexGeni(coord, GL_TEXTURE_GEN_MODE, func); if(func == GL_OBJECT_LINEAR) { glTexGenfv(coord, GL_OBJECT_PLANE, const_cast<GLfloat *>(plane.getValues())); } if(oldfunc == GL_NONE && oldbeacon == NULL) glEnable(gen); } else if(oldfunc != GL_NONE || oldbeacon != NULL) { glDisable(gen); } #endif }
void PhysicsPlaneGeom::setParams(const Vec4f &value ) { PhysicsPlaneGeomPtr tmpPtr(*this); dGeomPlaneSetParams(tmpPtr->id, value.x(), value.y(), value.z(), value.w()); PhysicsPlaneGeomBase::setParams(value); }
void mitk::VtkModel::DrawOpenGLGroup(int group, bool) { using sofa::core::loader::Material; using sofa::defaulttype::ResizableExtVector; using sofa::defaulttype::Vec4f; const VecCoord& vertices = this->getVertices(); const ResizableExtVector<Deriv>& normals = this->getVnormals(); const ResizableExtVector<Triangle>& triangles = this->getTriangles(); const ResizableExtVector<Quad>& quads = this->getQuads(); FaceGroup faceGroup; if (group == -1) { faceGroup.nbt = triangles.size(); faceGroup.nbq = quads.size(); } else { faceGroup = groups.getValue()[group]; } Material material = faceGroup.materialId != -1 ? materials.getValue()[faceGroup.materialId] : this->material.getValue(); if (material.useTexture && material.activated) { m_Textures[faceGroup.materialId]->Load(m_VtkRenderer); glEnable(GL_TEXTURE_2D); glTexCoordPointer(2, GL_FLOAT, 0, reinterpret_cast<const GLvoid*>(vertices.size() * sizeof(VecCoord::value_type) + normals.size() * sizeof(Deriv))); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } Vec4f ambient = material.useAmbient ? material.ambient : Vec4f(); Vec4f diffuse = material.useDiffuse ? material.diffuse : Vec4f(); Vec4f specular = material.useSpecular ? material.specular : Vec4f(); Vec4f emissive = material.useEmissive ? material.emissive : Vec4f(); float shininess = material.useShininess ? std::min(material.shininess, 128.0f) : 45.0f; if (shininess == 0.0f) { specular.clear(); shininess = 1.0f; } glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient.ptr()); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse.ptr()); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular.ptr()); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emissive.ptr()); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); if (faceGroup.nbt != 0) glDrawElements(GL_TRIANGLES, faceGroup.nbt * 3, GL_UNSIGNED_INT, reinterpret_cast<const GLvoid*>(faceGroup.tri0 * sizeof(Triangle))); if (faceGroup.nbq != 0) glDrawElements(GL_QUADS, faceGroup.nbq * 4, GL_UNSIGNED_INT, reinterpret_cast<const GLvoid*>(triangles.size() * sizeof(Triangle) + faceGroup.quad0 * sizeof(Quad))); if (material.useTexture && material.activated) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_2D); m_Textures[faceGroup.materialId]->PostRender(m_VtkRenderer); } }
void Render::RenderScene(Camera* pCamera, Scene* pScene, Texture* pRenderColor, Texture* pRenderDepth) { if(m_multiPass && m_pSlicedQuaxol && m_pOverdrawQuaxol && pRenderDepth && pRenderColor) { // 1st pass of color, depth to ([eyefbo,colorfbo], [eyedepth,depthfbo]) glDisable(GL_BLEND); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GEQUAL, 0.2f); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); WasGLErrorPlusPrint(); m_pSlicedQuaxol->StartUsing(); // TODO: calc this from the block size and the w near and far // currently tuned for -40 near, 40 far, 10 blocksize static Vec4f sliceRange(0.456f, 0.556f, 0.0f, 0.0f); GLuint hSliceShaderRange = m_pSlicedQuaxol->getUniform("sliceRange"); if(hSliceShaderRange != -1) { glUniform4fv(hSliceShaderRange, 1, sliceRange.raw()); WasGLErrorPlusPrint(); } m_pSlicedQuaxol->StopUsing(); //float savedWnear = pCamera->_wNear; //float savedWfar = pCamera->_wFar; //float savedWratio = pCamera->_wScreenSizeRatio; //static float sliceAmount = 0.334f; //float wRange = pCamera->_wFar - pCamera->_wNear; //float wPreNear = (1.0f - sliceAmount) * 0.5f * wRange; //pCamera->SetWProjection(savedWnear + wPreNear, savedWfar - wPreNear, 1.0f /*ratio*/); pScene->RenderQuaxols(pCamera, m_pSlicedQuaxol); pScene->RenderGroundPlane(pCamera); //pCamera->SetWProjection(savedWnear, savedWfar, savedWratio); // 2nd pass of depth - offset <= color blend to (overdrawfbo) glBindFramebuffer(GL_FRAMEBUFFER, m_overdrawColor->m_framebuffer_id); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_overdrawColor->m_texture_id, 0); //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, // GL_TEXTURE_2D, m_overdrawDepth->m_texture_id, 0); // waste? glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); // good opportunity to do order independent alpha // but first the stupid way glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //glBlendFunc(GL_SRC_ALPHA, GL_ONE); glDisable(GL_ALPHA_TEST); glDisable(GL_DEPTH_TEST); glDepthFunc(GL_ALWAYS); glDepthMask(GL_FALSE); WasGLErrorPlusPrint(); m_pOverdrawQuaxol->StartUsing(); GLuint hOverdrawShaderRange = m_pOverdrawQuaxol->getUniform("sliceRange"); if(hOverdrawShaderRange != -1) { glUniform4fv(hOverdrawShaderRange, 1, sliceRange.raw()); } m_pOverdrawQuaxol->StopUsing(); GLint hDepthTex = m_pOverdrawQuaxol->getUniform("texDepth"); if(hDepthTex != -1) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, pRenderDepth->GetTextureID()); WasGLErrorPlusPrint(); //glUniform1i(hDepthTex, 1); //WasGLErrorPlusPrint(); } pScene->RenderQuaxols(pCamera, m_pOverdrawQuaxol); //// 3rd additive fullscreen render overlay //// with capped blending to ([eyefbo,bb]) //RenderCompose(pCamera, pRenderColor, m_overdrawColor); // restore depth mask glDepthMask(GL_TRUE); } else { pScene->RenderEverything(pCamera); } }