/////////////////////////////////////////////////////////////////// // Scissor rectangle of water patches CBoundingBoxAligned TerrainRenderer::ScissorWater(const CMatrix3D &viewproj) { CBoundingBoxAligned scissor; for (size_t i = 0; i < m->visiblePatches.size(); ++i) { CPatchRData* data = m->visiblePatches[i]; const CBoundingBoxAligned& waterBounds = data->GetWaterBounds(); if (waterBounds.IsEmpty()) continue; CVector4D v1 = viewproj.Transform(CVector4D(waterBounds[0].X, waterBounds[1].Y, waterBounds[0].Z, 1.0f)); CVector4D v2 = viewproj.Transform(CVector4D(waterBounds[1].X, waterBounds[1].Y, waterBounds[0].Z, 1.0f)); CVector4D v3 = viewproj.Transform(CVector4D(waterBounds[0].X, waterBounds[1].Y, waterBounds[1].Z, 1.0f)); CVector4D v4 = viewproj.Transform(CVector4D(waterBounds[1].X, waterBounds[1].Y, waterBounds[1].Z, 1.0f)); CBoundingBoxAligned screenBounds; #define ADDBOUND(v1, v2, v3, v4) \ if (v1[2] >= -v1[3]) \ screenBounds += CVector3D(v1[0], v1[1], v1[2]) * (1.0f / v1[3]); \ else \ { \ float t = v1[2] + v1[3]; \ if (v2[2] > -v2[3]) \ { \ CVector4D c2 = v1 + (v2 - v1) * (t / (t - (v2[2] + v2[3]))); \ screenBounds += CVector3D(c2[0], c2[1], c2[2]) * (1.0f / c2[3]); \ } \ if (v3[2] > -v3[3]) \ { \ CVector4D c3 = v1 + (v3 - v1) * (t / (t - (v3[2] + v3[3]))); \ screenBounds += CVector3D(c3[0], c3[1], c3[2]) * (1.0f / c3[3]); \ } \ if (v4[2] > -v4[3]) \ { \ CVector4D c4 = v1 + (v4 - v1) * (t / (t - (v4[2] + v4[3]))); \ screenBounds += CVector3D(c4[0], c4[1], c4[2]) * (1.0f / c4[3]); \ } \ } ADDBOUND(v1, v2, v3, v4); ADDBOUND(v2, v1, v3, v4); ADDBOUND(v3, v1, v2, v4); ADDBOUND(v4, v1, v2, v3); #undef ADDBOUND if (screenBounds[0].X >= 1.0f || screenBounds[1].X <= -1.0f || screenBounds[0].Y >= 1.0f || screenBounds[1].Y <= -1.0f) continue; scissor += screenBounds; } return CBoundingBoxAligned(CVector3D(clamp(scissor[0].X, -1.0f, 1.0f), clamp(scissor[0].Y, -1.0f, 1.0f), -1.0f), CVector3D(clamp(scissor[1].X, -1.0f, 1.0f), clamp(scissor[1].Y, -1.0f, 1.0f), 1.0f)); }
void Utility::ScreenToWorld(CVector3D *out,CVector3D spos,CMatrix mProj,CMatrix mView,int w,int h){ CMatrix mVP; mVP.Viewport(0.0f,0.0f, static_cast<float>(w), static_cast<float>(h)); CVector4D o = (mView.getInverse() * mProj.getInverse() * mVP.getInverse()) * CVector4D(spos.x,spos.y,spos.z,1); *out = CVector3D(o.x/o.w,o.y/o.w,o.z/o.w); }
void Utility::WorldToScreen(CVector3D *out,CVector3D spos,CMatrix mProj,CMatrix mView,int w,int h) { CMatrix mVP; mVP.Viewport(0.0f, 0.0f, static_cast<float>(w), static_cast<float>(h)); CVector4D o = mVP * mProj * mView * CVector4D(spos.x,spos.y,spos.z,1); *out = CVector3D(o.x/o.w,o.y/o.w,1); }
void COBB::Transeform(CMatrix &mtx,bool trans) { for (int i=0;i<3;i++) { m_axis[i] = mtx * m_axis[i]; } if(trans) { CVector4D v = CVector4D(m_base_center.x,m_base_center.y,m_base_center.z,1.0); v = mtx * v; m_center = CVector3D(v.x,v.y,v.z); } m_mat = mtx; }
void CCamera::GetScreenCoordinates(const CVector3D& world, float& x, float& y) const { CMatrix3D transform = m_ProjMat * m_Orientation.GetInverse(); CVector4D screenspace = transform.Transform(CVector4D(world.X, world.Y, world.Z, 1.0f)); x = screenspace.m_X / screenspace.m_W; y = screenspace.m_Y / screenspace.m_W; x = (x + 1) * 0.5f * g_Renderer.GetWidth(); y = (1 - y) * 0.5f * g_Renderer.GetHeight(); }
void CMagic120Cell::fillHypercubeMap() { // Generate the 8 cube face centers. // The last rotation is required because of how we initially orient our 120-cell. double angle = -dihedral/2; CVector4D faces[8]; faces[0] = CVector4D( standardFaceOffset, 0, 0, 0 ); faces[0].rotate( 0, 2, angle ); faces[1] = CVector4D( -standardFaceOffset, 0, 0, 0 ); faces[1].rotate( 0, 2, angle ); faces[2] = CVector4D( 0, standardFaceOffset, 0, 0 ); faces[2].rotate( 0, 2, angle ); faces[3] = CVector4D( 0, -standardFaceOffset, 0, 0 ); faces[3].rotate( 0, 2, angle ); faces[4] = CVector4D( 0, 0, standardFaceOffset, 0 ); faces[4].rotate( 0, 2, angle ); faces[5] = CVector4D( 0, 0, -standardFaceOffset, 0 ); faces[5].rotate( 0, 2, angle ); faces[6] = CVector4D( 0, 0, 0, standardFaceOffset ); faces[6].rotate( 0, 2, angle ); faces[7] = CVector4D( 0, 0, 0, -standardFaceOffset ); faces[7].rotate( 0, 2, angle ); int count = 0; for( int f=0; f<8; f++ ) { for( int i=0; i<m_nCells; i++ ) { double magSquared = ( m_cells[i].getCenter() - faces[f] ).magSquared(); if( magSquared < 7 ) { m_hypercubeMap.insert( int_pair( i, f ) ); count++; } } } assert( count == m_nCells - 16 ); // There are 16 left. Put them in the last layer. for( int i=0; i<m_nCells; i++ ) { std::map<__int8,__int8>::iterator map_iterator; map_iterator = m_hypercubeMap.find( i ); if( map_iterator == m_hypercubeMap.end() ) m_hypercubeMap.insert( int_pair( i, 8 ) ); } }
int CLuaVector4Defs::Unm ( lua_State* luaVM ) { CLuaVector4D* pVector = NULL; CScriptArgReader argStream ( luaVM ); argStream.ReadUserData ( pVector ); if ( !argStream.HasErrors () ) { lua_pushvector ( luaVM, CVector4D () - *pVector ); return 1; } else { m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage() ); } lua_pushboolean ( luaVM, false ); return 1; }
void CMagic120Cell::generate4Cube() { // XXX - Clean up this code and make it shorter. // WOW! golden ratio shows up everywhere. const double c = standardFaceOffset /* * m_settings.m_cellDistance*/ / golden; m_hypercubePoints[0] = CVector4D( -c, c, -c, c ); m_hypercubePoints[1] = CVector4D( -c, c, c, c ); m_hypercubePoints[2] = CVector4D( c, c, c, c ); m_hypercubePoints[3] = CVector4D( c, c, -c, c ); m_hypercubePoints[4] = CVector4D( -c, -c, -c, c ); m_hypercubePoints[5] = CVector4D( -c, -c, c, c ); m_hypercubePoints[6] = CVector4D( c, -c, c, c ); m_hypercubePoints[7] = CVector4D( c, -c, -c, c ); m_hypercubePoints[8] = CVector4D( -c, c, -c, -c ); m_hypercubePoints[9] = CVector4D( -c, c, c, -c ); m_hypercubePoints[10] = CVector4D( c, c, c, -c ); m_hypercubePoints[11] = CVector4D( c, c, -c, -c ); m_hypercubePoints[12] = CVector4D( -c, -c, -c, -c ); m_hypercubePoints[13] = CVector4D( -c, -c, c, -c ); m_hypercubePoints[14] = CVector4D( c, -c, c, -c ); m_hypercubePoints[15] = CVector4D( c, -c, -c, -c ); // Same as 4 above but switch x/y and z/w values m_hypercubePoints[16] = CVector4D( c, -c, c, -c ); m_hypercubePoints[17] = CVector4D( c, -c, c, c ); m_hypercubePoints[18] = CVector4D( c, c, c, c ); m_hypercubePoints[19] = CVector4D( c, c, c, -c ); m_hypercubePoints[20] = CVector4D( -c, -c, c, -c ); m_hypercubePoints[21] = CVector4D( -c, -c, c, c ); m_hypercubePoints[22] = CVector4D( -c, c, c, c ); m_hypercubePoints[23] = CVector4D( -c, c, c, -c ); m_hypercubePoints[24] = CVector4D( c, -c, -c, -c ); m_hypercubePoints[25] = CVector4D( c, -c, -c, c ); m_hypercubePoints[26] = CVector4D( c, c, -c, c ); m_hypercubePoints[27] = CVector4D( c, c, -c, -c ); m_hypercubePoints[28] = CVector4D( -c, -c, -c, -c ); m_hypercubePoints[29] = CVector4D( -c, -c, -c, c ); m_hypercubePoints[30] = CVector4D( -c, c, -c, c ); m_hypercubePoints[31] = CVector4D( -c, c, -c, -c ); double angle = -dihedral/2; for( int i=0; i<32; i++ ) m_hypercubePoints[i].rotate( 0, 2, angle ); for( int i=0; i<32; i++ ) m_hypercubePointsCopy[i] = m_hypercubePoints[i]; }
IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateTangents) : m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW) { size_t numVertices = mdef->GetNumVertices(); m_Position.type = GL_FLOAT; m_Position.elems = 3; m_Array.AddAttribute(&m_Position); m_Normal.type = GL_FLOAT; m_Normal.elems = 3; m_Array.AddAttribute(&m_Normal); m_UVs.resize(mdef->GetNumUVsPerVertex()); for (size_t i = 0; i < mdef->GetNumUVsPerVertex(); i++) { m_UVs[i].type = GL_FLOAT; m_UVs[i].elems = 2; m_Array.AddAttribute(&m_UVs[i]); } if (gpuSkinning) { m_BlendJoints.type = GL_UNSIGNED_BYTE; m_BlendJoints.elems = 4; m_Array.AddAttribute(&m_BlendJoints); m_BlendWeights.type = GL_UNSIGNED_BYTE; m_BlendWeights.elems = 4; m_Array.AddAttribute(&m_BlendWeights); } if (calculateTangents) { // Generate tangents for the geometry:- m_Tangent.type = GL_FLOAT; m_Tangent.elems = 4; m_Array.AddAttribute(&m_Tangent); // floats per vertex; position + normal + tangent + UV*sets [+ GPUskinning] int numVertexAttrs = 3 + 3 + 4 + 2 * mdef->GetNumUVsPerVertex(); if (gpuSkinning) { numVertexAttrs += 8; } // the tangent generation can increase the number of vertices temporarily // so reserve a bit more memory to avoid reallocations in GenTangents (in most cases) std::vector<float> newVertices; newVertices.reserve(numVertexAttrs * numVertices * 2); // Generate the tangents ModelRenderer::GenTangents(mdef, newVertices, gpuSkinning); // how many vertices do we have after generating tangents? int newNumVert = newVertices.size() / numVertexAttrs; std::vector<int> remapTable(newNumVert); std::vector<float> vertexDataOut(newNumVert * numVertexAttrs); // re-weld the mesh to remove duplicated vertices int numVertices2 = WeldMesh(&remapTable[0], &vertexDataOut[0], &newVertices[0], newNumVert, numVertexAttrs); // Copy the model data to graphics memory:- m_Array.SetNumVertices(numVertices2); m_Array.Layout(); VertexArrayIterator<CVector3D> Position = m_Position.GetIterator<CVector3D>(); VertexArrayIterator<CVector3D> Normal = m_Normal.GetIterator<CVector3D>(); VertexArrayIterator<CVector4D> Tangent = m_Tangent.GetIterator<CVector4D>(); VertexArrayIterator<u8[4]> BlendJoints; VertexArrayIterator<u8[4]> BlendWeights; if (gpuSkinning) { BlendJoints = m_BlendJoints.GetIterator<u8[4]>(); BlendWeights = m_BlendWeights.GetIterator<u8[4]>(); } // copy everything into the vertex array for (int i = 0; i < numVertices2; i++) { int q = numVertexAttrs * i; Position[i] = CVector3D(vertexDataOut[q + 0], vertexDataOut[q + 1], vertexDataOut[q + 2]); q += 3; Normal[i] = CVector3D(vertexDataOut[q + 0], vertexDataOut[q + 1], vertexDataOut[q + 2]); q += 3; Tangent[i] = CVector4D(vertexDataOut[q + 0], vertexDataOut[q + 1], vertexDataOut[q + 2], vertexDataOut[q + 3]); q += 4; if (gpuSkinning) { for (size_t j = 0; j < 4; ++j) { BlendJoints[i][j] = (u8)vertexDataOut[q + 0 + 2 * j]; BlendWeights[i][j] = (u8)vertexDataOut[q + 1 + 2 * j]; } q += 8; } for (size_t j = 0; j < mdef->GetNumUVsPerVertex(); j++) { VertexArrayIterator<float[2]> UVit = m_UVs[j].GetIterator<float[2]>(); UVit[i][0] = vertexDataOut[q + 0 + 2 * j]; UVit[i][1] = vertexDataOut[q + 1 + 2 * j]; } } // upload vertex data m_Array.Upload(); m_Array.FreeBackingStore(); m_IndexArray.SetNumVertices(mdef->GetNumFaces() * 3); m_IndexArray.Layout(); VertexArrayIterator<u16> Indices = m_IndexArray.GetIterator(); size_t idxidx = 0; // reindex geometry and upload index for (size_t j = 0; j < mdef->GetNumFaces(); ++j) { Indices[idxidx++] = remapTable[j * 3 + 0]; Indices[idxidx++] = remapTable[j * 3 + 1]; Indices[idxidx++] = remapTable[j * 3 + 2]; } m_IndexArray.Upload(); m_IndexArray.FreeBackingStore(); } else { // Upload model without calculating tangents:- m_Array.SetNumVertices(numVertices); m_Array.Layout(); VertexArrayIterator<CVector3D> Position = m_Position.GetIterator<CVector3D>(); VertexArrayIterator<CVector3D> Normal = m_Normal.GetIterator<CVector3D>(); ModelRenderer::CopyPositionAndNormals(mdef, Position, Normal); for (size_t i = 0; i < mdef->GetNumUVsPerVertex(); i++) { VertexArrayIterator<float[2]> UVit = m_UVs[i].GetIterator<float[2]>(); ModelRenderer::BuildUV(mdef, UVit, i); } if (gpuSkinning) { VertexArrayIterator<u8[4]> BlendJoints = m_BlendJoints.GetIterator<u8[4]>(); VertexArrayIterator<u8[4]> BlendWeights = m_BlendWeights.GetIterator<u8[4]>(); for (size_t i = 0; i < numVertices; ++i) { const SModelVertex& vtx = mdef->GetVertices()[i]; for (size_t j = 0; j < 4; ++j) { BlendJoints[i][j] = vtx.m_Blend.m_Bone[j]; BlendWeights[i][j] = (u8)(255.f * vtx.m_Blend.m_Weight[j]); } } } m_Array.Upload(); m_Array.FreeBackingStore(); m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3); m_IndexArray.Layout(); ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator()); m_IndexArray.Upload(); m_IndexArray.FreeBackingStore(); } }
void CCinemaPath::Draw() const { DrawSpline(*this, CVector4D(0.2f, 0.2f, 1.f, 0.5f), 100, true); DrawSpline(m_TargetSpline, CVector4D(1.0f, 0.2f, 0.2f, 0.5f), 100, true); DrawNodes(CVector4D(0.5f, 1.0f, 0.f, 0.5f)); }
/** * Vector division by a scalar. */ template<typename TType> friend CVector4D operator/ (const CVector4D& cVector, TType tScalar) { return CVector4D(cVector) / tScalar; }
/** * Vector multiplication by a scalar. */ template<typename TType> friend CVector4D operator* (TType tScalar, const CVector4D& cVector) { return CVector4D(cVector) * tScalar; }
// Build vertex buffer for water vertices over our patch void CPatchRData::BuildWater() { PROFILE3("build water"); // number of vertices in each direction in each patch ENSURE((PATCH_SIZE % water_cell_size) == 0); if (m_VBWater) { g_VBMan.Release(m_VBWater); m_VBWater = 0; } if (m_VBWaterIndices) { g_VBMan.Release(m_VBWaterIndices); m_VBWaterIndices = 0; } m_WaterBounds.SetEmpty(); // We need to use this to access the water manager or we may not have the // actual values but some compiled-in defaults CmpPtr<ICmpWaterManager> cmpWaterManager(*m_Simulation, SYSTEM_ENTITY); if (!cmpWaterManager) return; // Build data for water std::vector<SWaterVertex> water_vertex_data; std::vector<GLushort> water_indices; u16 water_index_map[PATCH_SIZE+1][PATCH_SIZE+1]; memset(water_index_map, 0xFF, sizeof(water_index_map)); // TODO: This is not (yet) exported via the ICmp interface so... we stick to these values which can be compiled in defaults WaterManager* WaterMgr = g_Renderer.GetWaterManager(); if (WaterMgr->m_NeedsFullReloading && !g_AtlasGameLoop->running) { WaterMgr->m_NeedsFullReloading = false; WaterMgr->CreateSuperfancyInfo(m_Simulation); } CPatch* patch = m_Patch; CTerrain* terrain = patch->m_Parent; ssize_t mapSize = (size_t)terrain->GetVerticesPerSide(); ssize_t x1 = m_Patch->m_X*PATCH_SIZE; ssize_t z1 = m_Patch->m_Z*PATCH_SIZE; // build vertices, uv, and shader varying for (ssize_t z = 0; z < PATCH_SIZE; z += water_cell_size) { for (ssize_t x = 0; x <= PATCH_SIZE; x += water_cell_size) { // Check that the edge at x is partially underwater float startTerrainHeight[2] = { terrain->GetVertexGroundLevel(x+x1, z+z1), terrain->GetVertexGroundLevel(x+x1, z+z1 + water_cell_size) }; float startWaterHeight[2] = { cmpWaterManager->GetExactWaterLevel(x+x1, z+z1), cmpWaterManager->GetExactWaterLevel(x+x1, z+z1 + water_cell_size) }; if (startTerrainHeight[0] >= startWaterHeight[0] && startTerrainHeight[1] >= startWaterHeight[1]) continue; // Move x back one cell (unless at start of patch), then scan rightwards bool belowWater = true; ssize_t stripStart; for (stripStart = x = std::max(x-water_cell_size, (ssize_t)0); x <= PATCH_SIZE; x += water_cell_size) { // If this edge is not underwater, and neither is the previous edge // (i.e. belowWater == false), then stop this strip since we've reached // a cell that's entirely above water float terrainHeight[2] = { terrain->GetVertexGroundLevel(x+x1, z+z1), terrain->GetVertexGroundLevel(x+x1, z+z1 + water_cell_size) }; float waterHeight[2] = { cmpWaterManager->GetExactWaterLevel(x+x1, z+z1), cmpWaterManager->GetExactWaterLevel(x+x1, z+z1 + water_cell_size) }; if (terrainHeight[0] >= waterHeight[0] && terrainHeight[1] >= waterHeight[1]) { if (!belowWater) break; belowWater = false; } else belowWater = true; // Edge (x,z)-(x,z+1) is at least partially underwater, so extend the water plane strip across it // Compute vertex data for the 2 points on the edge for (int j = 0; j < 2; j++) { // Check if we already computed this vertex from an earlier strip if (water_index_map[z+j*water_cell_size][x] != 0xFFFF) continue; SWaterVertex vertex; terrain->CalcPosition(x+x1, z+z1 + j*water_cell_size, vertex.m_Position); float depth = waterHeight[j] - vertex.m_Position.Y; vertex.m_Position.Y = waterHeight[j]; m_WaterBounds += vertex.m_Position; // NB: Usually this factor is view dependent, but for performance reasons // we do not take it into account with basic non-shader based water. // Average constant Fresnel effect for non-fancy water float alpha = clamp(depth / WaterMgr->m_WaterFullDepth + WaterMgr->m_WaterAlphaOffset, WaterMgr->m_WaterAlphaOffset, WaterMgr->m_WaterMaxAlpha); // Split the depth data across 24 bits, so the fancy-water shader can reconstruct // the depth value while the simple-water can just use the precomputed alpha float depthInt = floor(depth); float depthFrac = depth - depthInt; vertex.m_DepthData = SColor4ub( u8(clamp(depthInt, 0.0f, 255.0f)), u8(clamp(-depthInt, 0.0f, 255.0f)), u8(clamp(depthFrac*255.0f, 0.0f, 255.0f)), u8(clamp(alpha*255.0f, 0.0f, 255.0f))); int tx = x+x1; int ty = z+z1 + j*water_cell_size; if (g_AtlasGameLoop->running) { // currently no foam is used so push whatever vertex.m_WaterData = CVector4D(0.0f,0.0f,0.0f,0.0f); } else { vertex.m_WaterData = CVector4D(WaterMgr->m_WaveX[tx + ty*mapSize], WaterMgr->m_WaveZ[tx + ty*mapSize], WaterMgr->m_DistanceToShore[tx + ty*mapSize], WaterMgr->m_FoamFactor[tx + ty*mapSize]); } water_index_map[z+j*water_cell_size][x] = water_vertex_data.size(); water_vertex_data.push_back(vertex); } // If this was not the first x in the strip, then add a quad // using the computed vertex data if (x <= stripStart) continue; water_indices.push_back(water_index_map[z + water_cell_size][x - water_cell_size]); water_indices.push_back(water_index_map[z][x - water_cell_size]); water_indices.push_back(water_index_map[z][x]); water_indices.push_back(water_index_map[z + water_cell_size][x]); } } } // no vertex buffers if no data generated if (water_indices.size() == 0) return; // allocate vertex buffer m_VBWater = g_VBMan.Allocate(sizeof(SWaterVertex), water_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER); m_VBWater->m_Owner->UpdateChunkVertices(m_VBWater, &water_vertex_data[0]); // Construct indices buffer m_VBWaterIndices = g_VBMan.Allocate(sizeof(GLushort), water_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER); m_VBWaterIndices->m_Owner->UpdateChunkVertices(m_VBWaterIndices, &water_indices[0]); }