forked from Mirrors/openclonk
Rope: Draw the rope with GL_QUAD_STRIP
parent
1ef0f3ce41
commit
a556dc1798
|
@ -21,6 +21,15 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
struct Vertex {
|
||||
Vertex() {}
|
||||
Vertex(float x, float y): x(x), y(y) {}
|
||||
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
// For use in initializer list
|
||||
C4Real ObjectDistance(C4Object* first, C4Object* second)
|
||||
{
|
||||
C4Real dx = second->fix_x - first->fix_x;
|
||||
|
@ -28,8 +37,26 @@ namespace
|
|||
return ftofix(sqrt(fixtof(dx*dx + dy*dy))); // TODO: Replace by integer sqrt
|
||||
}
|
||||
|
||||
// To be used by the Solve() template function:
|
||||
C4Object* GetObject(C4RopeSegment* segment) { return NULL; }
|
||||
C4Object* GetObject(C4RopeEnd* end) { return end->GetObject(); }
|
||||
|
||||
// Helper function for Draw: determines vertex positions for one segment
|
||||
void VertexPos(Vertex& out1, Vertex& out2, Vertex& out3, Vertex& out4,
|
||||
const Vertex& v1, const Vertex& v2)
|
||||
{
|
||||
static const float w = 5.0f; // segment width
|
||||
const float l = sqrt( (v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y));
|
||||
|
||||
out1.x = v1.x + w/2.0f * (v1.y - v2.y) / l;
|
||||
out1.y = v1.y - w/2.0f * (v1.x - v2.x) / l;
|
||||
out2.x = v1.x - w/2.0f * (v1.y - v2.y) / l;
|
||||
out2.y = v1.y + w/2.0f * (v1.x - v2.x) / l;
|
||||
out3.x = v2.x + w/2.0f * (v1.y - v2.y) / l;
|
||||
out3.y = v2.y - w/2.0f * (v1.x - v2.x) / l;
|
||||
out4.x = v2.x - w/2.0f * (v1.y - v2.y) / l;
|
||||
out4.y = v2.y + w/2.0f * (v1.x - v2.x) / l;
|
||||
}
|
||||
}
|
||||
|
||||
C4RopeSegment::C4RopeSegment(C4Real x, C4Real y, C4Real m):
|
||||
|
@ -125,6 +152,9 @@ void C4RopeEnd::Execute(C4Real dt)
|
|||
{
|
||||
obj->xdir += dt * fx / obj->Mass;
|
||||
obj->ydir += dt * fy / obj->Mass;
|
||||
|
||||
// TODO: Remove contact attachment if there is much force in opposite direction
|
||||
// TODO: V redirection
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -143,12 +173,12 @@ void C4RopeEnd::Execute(C4Real dt)
|
|||
|
||||
C4Rope::C4Rope(C4Object* first_obj, C4Object* second_obj, int32_t n_segments):
|
||||
n_segments(n_segments), l(ObjectDistance(first_obj, second_obj) / (n_segments + 1)),
|
||||
k(Fix1*3), rho(Fix1*3), /* TODO: proper default values for k and rho */ n_iterations(20)
|
||||
k(Fix1*3), eta(Fix1*3), /* TODO: proper default values for k and eta */ n_iterations(20)
|
||||
{
|
||||
if(!PathFree(first_obj->GetX(), first_obj->GetY(), second_obj->GetX(), second_obj->GetY()))
|
||||
throw C4RopeError("Failed to create rope: Path between objects is blocked");
|
||||
throw C4RopeError("Path between objects is blocked");
|
||||
if(n_segments < 1)
|
||||
throw C4RopeError("Failed to create rope: Segments < 1 given");
|
||||
throw C4RopeError("Segments < 1 given");
|
||||
|
||||
// TODO: Have this as an array, not as a linked list -- it's ~static after all!
|
||||
const C4Real m(Fix1);
|
||||
|
@ -201,8 +231,10 @@ void C4Rope::Solve(TRopeType1* prev, TRopeType2* next) //C4RopeSegment* prev, C4
|
|||
}
|
||||
|
||||
// Inner friction
|
||||
fx += (prev->GetVx() - next->GetVx()) * rho;
|
||||
fy += (prev->GetVy() - next->GetVy()) * rho;
|
||||
fx += (prev->GetVx() - next->GetVx()) * eta;
|
||||
fy += (prev->GetVy() - next->GetVy()) * eta;
|
||||
|
||||
// Could add air/water friction here
|
||||
|
||||
// Apply forces to masses. Don't apply gravity to objects since it's applied already in C4Object execution.
|
||||
prev->AddForce(-fx, -fy + (GetObject(prev) ? Fix0 : prev->GetMass() * ::Landscape.Gravity/5));
|
||||
|
@ -232,41 +264,44 @@ void C4Rope::Execute()
|
|||
|
||||
void C4Rope::Draw(C4Facet& cgo)
|
||||
{
|
||||
struct Vertex
|
||||
Vertex Tmp[4];
|
||||
Vertex Vertices[n_segments*2+4];
|
||||
|
||||
VertexPos(Vertices[0], Vertices[1], Tmp[0], Tmp[1],
|
||||
Vertex(fixtof(front->GetX()), fixtof(front->GetY())),
|
||||
Vertex(fixtof(front->segment->GetX()), fixtof(front->segment->GetY())));
|
||||
|
||||
unsigned int i = 2;
|
||||
for(C4RopeSegment* cur = front->segment; cur != NULL; cur = cur->next, i += 2)
|
||||
{
|
||||
float x, y;
|
||||
};
|
||||
Vertex v1(fixtof(cur->GetX()),
|
||||
fixtof(cur->GetY()));
|
||||
Vertex v2(fixtof(cur->next ? cur->next->GetX() : back->GetX()),
|
||||
fixtof(cur->next ? cur->next->GetY() : back->GetY()));
|
||||
|
||||
// TODO: Change this so that it draws a quad strip
|
||||
Vertex Vertices[n_segments*4+4]; unsigned int i = 0;
|
||||
for(C4RopeSegment* cur = front->segment; cur != NULL; cur = cur->next)
|
||||
{
|
||||
float prev_x = fixtof(cur->prev ? cur->prev->GetX() : front->GetX());
|
||||
float prev_y = fixtof(cur->prev ? cur->prev->GetY() : front->GetY());
|
||||
float x = fixtof(cur->GetX());
|
||||
float y = fixtof(cur->GetY());
|
||||
// Obtain vertex positions
|
||||
// TODO: If angle > 90 degrees (dot product negative), then swap indices below
|
||||
// Might need to adapt texture coordinates for this segment as well to avoid graphical glitch
|
||||
// when going from 89 to 91 degrees.
|
||||
VertexPos(Tmp[2], Tmp[3], Vertices[i+2], Vertices[i+3], v1, v2);
|
||||
Tmp[2].x = (Tmp[0].x + Tmp[2].x)/2.0f;
|
||||
Tmp[2].y = (Tmp[0].y + Tmp[2].y)/2.0f;
|
||||
Tmp[3].x = (Tmp[1].x + Tmp[3].x)/2.0f;
|
||||
Tmp[3].y = (Tmp[1].y + Tmp[3].y)/2.0f;
|
||||
|
||||
float l = sqrt( (prev_x - x) * (prev_x - x) + (prev_y - y) * (prev_y - y));
|
||||
// renormalize
|
||||
float dx = Tmp[3].x - Tmp[2].x;
|
||||
float dy = Tmp[3].y - Tmp[2].y;
|
||||
float dx2 = Vertices[i-1].x - Vertices[i-2].x;
|
||||
float dy2 = Vertices[i-1].y - Vertices[i-2].y;
|
||||
const float d = (dx2*dx2+dy2*dy2)/(dx*dx2+dy*dy2);
|
||||
Vertices[i ].x = ( (Tmp[2].x + Tmp[3].x)/2.0f) - (Tmp[3].x - Tmp[2].x)*d/2.0f;
|
||||
Vertices[i ].y = ( (Tmp[2].y + Tmp[3].y)/2.0f) - (Tmp[3].y - Tmp[2].y)*d/2.0f;
|
||||
Vertices[i+1].x = ( (Tmp[2].x + Tmp[3].x)/2.0f) + (Tmp[3].x - Tmp[2].x)*d/2.0f;
|
||||
Vertices[i+1].y = ( (Tmp[2].y + Tmp[3].y)/2.0f) + (Tmp[3].y - Tmp[2].y)*d/2.0f;
|
||||
|
||||
float x1 = prev_x + 2.5 * (prev_y - y) / l;
|
||||
float x2 = prev_x - 2.5 * (prev_y - y) / l;
|
||||
float x3 = x - 2.5 * (prev_y - y) / l;
|
||||
float x4 = x + 2.5 * (prev_y - y) / l;
|
||||
|
||||
float y1 = prev_y - 2.5 * (prev_x - x) / l;
|
||||
float y2 = prev_y + 2.5 * (prev_x - x) / l;
|
||||
float y3 = y + 2.5 * (prev_x - x) / l;
|
||||
float y4 = y - 2.5 * (prev_x - x) / l;
|
||||
|
||||
Vertices[i].x = x1;
|
||||
Vertices[i].y = y1;
|
||||
Vertices[i+1].x = x2;
|
||||
Vertices[i+1].y = y2;
|
||||
Vertices[i+2].x = x3;
|
||||
Vertices[i+2].y = y3;
|
||||
Vertices[i+3].x = x4;
|
||||
Vertices[i+3].y = y4;
|
||||
i += 4;
|
||||
Tmp[0] = Vertices[i+2];
|
||||
Tmp[1] = Vertices[i+3];
|
||||
}
|
||||
|
||||
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
|
||||
|
@ -275,7 +310,7 @@ void C4Rope::Draw(C4Facet& cgo)
|
|||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDrawArrays(GL_QUADS, 0, n_segments*4);
|
||||
glDrawArrays(GL_QUAD_STRIP, 0, n_segments*2+4);
|
||||
}
|
||||
|
||||
C4RopeList::C4RopeList()
|
||||
|
|
|
@ -104,9 +104,14 @@ private:
|
|||
|
||||
int32_t n_segments;
|
||||
|
||||
// TODO: Add a "dynlength" feature which adapts the spring length to the
|
||||
// distance of the two ends, up to a maximum... and/or callbacks to script
|
||||
// when the length should be changed so that script can do it (and maybe
|
||||
// play an animation, such as for the lift tower).
|
||||
|
||||
C4Real l; // spring length in equilibrium
|
||||
C4Real k; // spring constant
|
||||
C4Real rho; // friction constant
|
||||
C4Real eta; // inner friction constant
|
||||
|
||||
C4RopeEnd* front;
|
||||
C4RopeEnd* back;
|
||||
|
|
Loading…
Reference in New Issue