Skip to content

Instantly share code, notes, and snippets.

@xl1
Created October 21, 2012 15:22
Show Gist options
  • Save xl1/3927259 to your computer and use it in GitHub Desktop.
Save xl1/3927259 to your computer and use it in GitHub Desktop.
ゴルフのやつ
// http://jsdo.it/xl1/aTTK
#define REFLECT_MAX 10
#define NODE_LEN 10
precision mediump float;
struct Segment {
vec2 start;
vec2 dir;
float len;
};
struct Circle {
vec2 center;
float radius;
};
struct Intersect {
float at;
vec2 edge;
};
const vec4 border = vec4(300.0, 170.0, 0.0, 100.0);
const vec2 handleSize = vec2(20.0, 20.0);
const vec2 origin = vec2(200.0, 300.0);
uniform vec2 u_textureSize;
varying vec2 v_texCoord;
uniform float timing;
vec2 nodes(int idx){
if(idx == 1) return vec2(160.0, 180.0);
if(idx == 2) return vec2( 80.0, 180.0);
if(idx == 3) return vec2( 30.0, 100.0);
if(idx == 4) return vec2( 20.0, 20.0);
if(idx == 5) return vec2( 90.0, 20.0);
if(idx == 6) return vec2( 90.0, 115.0);
if(idx == 7) return vec2(180.0, 115.0);
if(idx == 8) return vec2(250.0, 170.0);
if(idx == 9) return vec2(240.0, 300.0);
return vec2(160.0, 300.0);
}
Intersect intersectSegments(Segment a, Segment b){
vec2 start = b.start - a.start;
vec3 prod = cross(
vec3(a.dir.x, b.dir.x, start.x),
vec3(a.dir.y, b.dir.y, start.y)
);
if(abs(prod.z) > 1e-6){
float ratioA = -prod.x / prod.z;
float ratioB = prod.y / prod.z;
if(0.0 < ratioA && ratioA < a.len && 0.0 < ratioB && ratioB < b.len){
return Intersect(ratioA - 1e-4, b.dir);
}
}
return Intersect(a.len, vec2(0.0));
}
Intersect intersectCircle(Segment a, Circle c){
vec2 cstart = c.center - a.start;
vec2 cend = c.center - (a.start + a.len * a.dir);
float dist = abs(a.dir.x * cstart.y - a.dir.y * cstart.x);
float pstart = dot(a.dir, cstart);
float pend = dot(a.dir, cend);
if(dist < c.radius && pstart * pend < 0.0){
float at = pstart - sqrt(c.radius * c.radius - dist * dist);
return Intersect(at, normalize(at * a.dir - c.center).yx * vec2(-1.0, 1.0));
}
return Intersect(a.len, vec2(0.0));
}
bool inField(vec2 pos){
bool result = false;
Segment ray = Segment(pos, vec2(1.0, 0.0), 400.0);
for(int i = 0; i < NODE_LEN; i++){
vec2 ed = nodes(i+1) - nodes(i);
Segment edge = Segment(nodes(i), normalize(ed), length(ed));
Intersect isc = intersectSegments(ray, edge);
if(isc.at < ray.len) result = !result;
}
return result;
}
bool inArrow(vec2 pos, Segment arrow){
vec2 p = pos - arrow.start;
float xprod = abs(arrow.dir.x * p.y - arrow.dir.y * p.x);
float dprod = dot(arrow.dir, p);
if(dprod < 0.0 || arrow.len < dprod) return false;
if(dprod > arrow.len * 0.2){
return xprod < 0.06 * arrow.len;
} else {
return xprod < 0.6 * length(p);
}
}
bool inCircle(vec2 pos, Circle circle){
return distance(pos, circle.center) < circle.radius;
}
bool chase(inout Segment loc, Circle goal){
for(int j = 0; j < REFLECT_MAX; j++){
Intersect isc = Intersect(loc.len, vec2(0.0));
for(int i = 0; i < NODE_LEN; i++){
vec2 ed = nodes(i+1) - nodes(i);
Segment edge = Segment(nodes(i), normalize(ed), length(ed));
Intersect iscLocal = intersectSegments(loc, edge);
if(iscLocal.at < isc.at) isc = iscLocal;
}
Intersect iscgoal = intersectCircle(loc, goal);
if(iscgoal.at < isc.at){
loc.start += loc.dir * iscgoal.at;
loc.dir = normalize(goal.center - loc.start);
loc.len = distance(goal.center, loc.start);
return true;
}
loc.len -= isc.at;
loc.start += loc.dir * isc.at;
loc.dir = 2.0 * dot(loc.dir, isc.edge) * isc.edge - loc.dir;
}
return false;
}
void main(){
vec2 handle = u_textureSize - vec2(border[1], border[2]) - (handleSize * 0.5) - origin;
vec2 position = v_texCoord * u_textureSize;
Circle goal = Circle(vec2(50.0, 40.0), 12.0);
if(timing == 0.0){
Segment arrow = Segment(
origin,
normalize(handle),
length(handle)
);
if(inArrow(position, arrow)){
gl_FragColor = vec4(0.9, 0.1, 0.1, 1.0);
return;
}
}
Segment loc = Segment(
origin,
-normalize(handle),
length(handle) * timing
);
bool goaled = chase(loc, goal);
if(!goaled && distance(loc.start, position) < 6.0){
gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0);
} else if(inCircle(position, goal)){
if(goaled){
gl_FragColor = vec4(0.2, 0.9, 0.5, 1.0);
} else {
gl_FragColor = vec4(0.4, 0.0, 0.0, 1.0);
}
} else if(inField(position)) {
gl_FragColor = vec4(0.3, 0.6, 0.2, 1.0);
} else if(position.x < 270.0 && position.y < 310.0) {
gl_FragColor = vec4(0.9, 0.7, 0.4, 1.0);
} else {
gl_FragColor = vec4(0.0);
}
}
attribute vec4 a_position;
attribute vec2 a_texCoord;
uniform mat4 u_projectionMatrix;
varying vec2 v_texCoord;
void main(){
v_texCoord = a_texCoord;
gl_Position = u_projectionMatrix * a_position;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment