[solved] Can you post your FPS result please ?

General discussion for topics related to the FreeBASIC project or its community.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

[solved] Can you post your FPS result please ?

Post by D.J.Peters »

Can you post your FPS result please ?

I ask here because I feel my GPU is slow and I got only one feedback in tips and tricks.

It would be nice if you run this OpenGL shader and tell me your frames per seconds and the GPU modell you are using.

The CPU usage is not measurable here so my GPU seams to be runs on it's limit.

With the current screenres setting I get round about 20 FPS.

Insside the web browser with WebGL (OpenGL ES) on shadertoy.com I get only 3-5 FPS (same shader code)

Is it a normal result or not ?

Thank you.

Joshy

Code: Select all

dim as string SCODE
SCODE &= !"// Mountains. By David Hoskins - 2013 \n"
SCODE &= !"// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. \n"
SCODE &= !"// https://www.shadertoy.com/view/4slGD4 \n"
SCODE &= !"// A ray-marched version of my terrain renderer which uses \n"
SCODE &= !"// streaming texture normals for speed:- \n"
SCODE &= !"// http://www.youtube.com/watch?v=qzkBnCBpQAM \n"
SCODE &= !"// It uses binary subdivision to accurately find the height map. \n"
SCODE &= !"// Lots of thanks to Iñigo and his noise functions"
SCODE &= !"// Video of my OpenGL version that  \n"
SCODE &= !"// http://www.youtube.com/watch?v=qzkBnCBpQAM \n"
SCODE &= !"// Stereo version code thanks to Croqueteer :) \n"

SCODE &= !"//#define STEREO \n" ' <--- !!! change it if you have 3D glasses

SCODE &= !"float treeLine = 0.0; \n"
SCODE &= !"float treeCol = 0.0; \n"
SCODE &= !"vec3 sunLight  = normalize( vec3(  0.4, 0.4,  0.48 ) ); \n"
SCODE &= !"vec3 sunColour = vec3(1.0, .9, .83); \n"
SCODE &= !"float specular = 0.0; \n"
SCODE &= !"vec3 cameraPos; \n"
SCODE &= !"float ambient; \n"
SCODE &= !"vec2 add = vec2(1.0, 0.0); \n"

SCODE &= !"#define MOD2 vec2(3.07965, 7.4235) \n"
SCODE &= !"#define MOD3 vec3(3.07965, 7.1235, 4.998784) \n"

SCODE &= !"// This peturbs the fractal positions for each iteration down... \n"
SCODE &= !"// Helps make nice twisted landscapes... \n"
SCODE &= !"const mat2 rotate2D = mat2(1.3623, 1.7531, -1.7131, 1.4623); \n"

SCODE &= !"float Hash12(vec2 p) { \n"
SCODE &= !"  p  = fract(p / MOD2); \n"
SCODE &= !"  p += dot(p.xy, p.yx+19.19); \n"
SCODE &= !"  return fract(p.x * p.y); \n"
SCODE &= !"} \n"

SCODE &= !"vec2 Hash22(vec2 p) { \n"
SCODE &= !"  vec3 p3 = fract(vec3(p.xyx) / MOD3); \n"
SCODE &= !"  p3 += dot(p3.zxy, p3.yxz+19.19); \n"
SCODE &= !"  return fract(vec2(p3.x * p3.y, p3.z*p3.x)); \n"
SCODE &= !"} \n"

SCODE &= !"float Noise( in vec2 x) { \n"
SCODE &= !"  vec2 p = floor(x); \n"
SCODE &= !"  vec2 f = fract(x); \n"
SCODE &= !"  f = f*f*(3.0-2.0*f); \n"
SCODE &= !"  float res = mix(mix( Hash12(p         ), Hash12(p + add.xy),f.x), \n"
SCODE &= !"                  mix( Hash12(p + add.yx), Hash12(p + add.xx),f.x), \n"
SCODE &= !"                  f.y); \n"
SCODE &= !"  return res; \n"
SCODE &= !"} \n"

SCODE &= !"vec2 Noise2(in vec2 x) { \n"
SCODE &= !"  vec2 p = floor(x); \n"
SCODE &= !"  vec2 f = fract(x); \n"
SCODE &= !"  f = f*f*(3.0-2.0*f); \n"
SCODE &= !"  float n = p.x + p.y * 57.0; \n"
SCODE &= !"  vec2 res = mix(mix( Hash22(p         ), Hash22(p + add.xy),f.x), \n"
SCODE &= !"                 mix( Hash22(p + add.yx), Hash22(p + add.xx),f.x), \n"
SCODE &= !"                 f.y); \n"
SCODE &= !"  return res; \n"
SCODE &= !"} \n"

SCODE &= !"float Trees(vec2 p) { \n"
SCODE &= !"  return Noise(p*13.0)*treeLine; \n"
SCODE &= !"} \n"

SCODE &= !"//-------------------------------------------------------------------------- \n"
SCODE &= !"// Low def version for ray-marching through the height field... \n"
SCODE &= !"// Thanks to IQ for all the noise stuff... \n"
SCODE &= !"float Terrain( in vec2 p) { \n"
SCODE &= !"  vec2 pos = p*0.05; \n"
SCODE &= !"  float w = (Noise(pos*.25)*0.75+.15); \n"
SCODE &= !"  w = 66.0 * w * w; \n"
SCODE &= !"  vec2 dxy = vec2(0.0, 0.0); \n"
SCODE &= !"  float f = .0; \n"
SCODE &= !"  for (int i = 0; i < 5; i++) \n"
SCODE &= !"  { \n"
SCODE &= !"    f += w * Noise(pos); \n"
SCODE &= !"    w = -w * 0.4;  //...Flip negative and positive for variation \n"
SCODE &= !"    pos = rotate2D * pos; \n"
SCODE &= !"  } \n"
SCODE &= !"  float ff = Noise(pos*.002); \n"
SCODE &= !"  f += pow(abs(ff), 5.0)*275.-5.0; \n"
SCODE &= !"  return f; \n"
SCODE &= !"} \n"

SCODE &= !"//-------------------------------------------------------------------------- \n"
SCODE &= !"// Map to lower resolution for height field mapping for Scene function... \n"
SCODE &= !"float Map(in vec3 p) { \n"
SCODE &= !"  float h = Terrain(p.xz); \n"
SCODE &= !"  float ff = Noise(p.xz*.3) + Noise(p.xz*3.3)*.5; \n"
SCODE &= !"  treeLine = smoothstep(ff, .0+ff*2.0, h) * smoothstep(1.0+ff*3.0, .4+ff, h) ; \n"
SCODE &= !"  treeCol = Trees(p.xz); \n"
SCODE &= !"  h += treeCol; \n"
SCODE &= !"  return p.y - h; \n"
SCODE &= !"} \n"

SCODE &= !"//-------------------------------------------------------------------------- \n"
SCODE &= !"// High def version only used for grabbing normal information. \n"
SCODE &= !"float Terrain2( in vec2 p){ \n"
SCODE &= !"  // There's some real magic numbers in here!  \n"
SCODE &= !"  // The Noise calls add large mountain ranges for more variation over distances... \n"
SCODE &= !"  vec2 pos = p*0.05; \n"
SCODE &= !"  float w = (Noise(pos*.25)*0.75+.15); \n"
SCODE &= !"  w = 66.0 * w * w; \n"
SCODE &= !"  vec2 dxy = vec2(0.0, 0.0); \n"
SCODE &= !"  float f = .0; \n"
SCODE &= !"  for (int i = 0; i < 5; i++) { \n"
SCODE &= !"    f += w * Noise(pos); \n"
SCODE &= !"    w =  - w * 0.4;  //...Flip negative and positive for varition      \n"
SCODE &= !"    pos = rotate2D * pos; \n"
SCODE &= !"  } \n"
SCODE &= !"  float ff = Noise(pos*.002); \n"
SCODE &= !"  f += pow(abs(ff), 5.0)*275.-5.0; \n"
SCODE &= !"  treeCol = Trees(p); \n"
SCODE &= !"  f += treeCol; \n"
SCODE &= !"  if (treeCol > 0.0) return f; \n"
SCODE &= !"  // That's the last of the low resolution, now go down further for the Normal data... \n"
SCODE &= !"  for (int i = 0; i < 6; i++) { \n"
SCODE &= !"    f += w * Noise(pos); \n"
SCODE &= !"    w =  - w * 0.4; \n"
SCODE &= !"    pos = rotate2D * pos; \n"
SCODE &= !"  } \n"
SCODE &= !"  return f; \n"
SCODE &= !"} \n"

SCODE &= !"//-------------------------------------------------------------------------- \n"
SCODE &= !"float FractalNoise(in vec2 xy){ \n"
SCODE &= !"  float w = .7; \n"
SCODE &= !"  float f = 0.0; \n"
SCODE &= !"  for (int i = 0; i < 4; i++) { \n"
SCODE &= !"    f += Noise(xy) * w; \n"
SCODE &= !"    w *= 0.5; \n"
SCODE &= !"    xy *= 2.7; \n"
SCODE &= !"  } \n"
SCODE &= !"  return f; \n"
SCODE &= !"} \n"

SCODE &= !"//-------------------------------------------------------------------------- \n"
SCODE &= !"// Simply Perlin clouds that fade to the horizon... \n"
SCODE &= !"// 200 units above the ground... \n"
SCODE &= !"vec3 GetClouds(in vec3 sky, in vec3 rd) { \n"
SCODE &= !"  if (rd.y < 0.01) return sky; \n"
SCODE &= !"  float v = (200.0-cameraPos.y)/rd.y; \n"
SCODE &= !"  rd.xz *= v; \n"
SCODE &= !"  rd.xz += cameraPos.xz; \n"
SCODE &= !"  rd.xz *= .010; \n"
SCODE &= !"  float f = (FractalNoise(rd.xz) -.55) * 5.0; \n"
SCODE &= !"  // Uses the ray's y component for horizon fade of fixed colour clouds... \n"
SCODE &= !"  sky = mix(sky, vec3(.55, .55, .52), clamp(f*rd.y-.1, 0.0, 1.0)); \n"
SCODE &= !"  return sky; \n"
SCODE &= !"} \n"

SCODE &= !"//-------------------------------------------------------------------------- \n"
SCODE &= !"// Grab all sky information for a given ray from camera \n"
SCODE &= !"vec3 GetSky(in vec3 rd){ \n"
SCODE &= !"  float sunAmount = max( dot( rd, sunLight), 0.0 ); \n"
SCODE &= !"  float v = pow(1.0-max(rd.y,0.0),5.)*.5; \n"
SCODE &= !"  vec3  sky = vec3(v*sunColour.x*0.4+0.18, v*sunColour.y*0.4+0.22, v*sunColour.z*0.4+.4); \n"
SCODE &= !"  // Wide glare effect... \n"
SCODE &= !"  sky = sky + sunColour * pow(sunAmount, 6.5)*.32; \n"
SCODE &= !"  // Actual sun... \n"
SCODE &= !"  sky = sky+ sunColour * min(pow(sunAmount, 1150.0), .3)*.65; \n"
SCODE &= !"  return sky; \n"
SCODE &= !"} \n"

SCODE &= !"//-------------------------------------------------------------------------- \n"
SCODE &= !"// Merge mountains into the sky background for correct disappearance... \n"
SCODE &= !"vec3 ApplyFog( in vec3  rgb, in float dis, in vec3 dir){ \n"
SCODE &= !"  float fogAmount = exp(-dis* 0.00005); \n"
SCODE &= !"  return mix(GetSky(dir), rgb, fogAmount ); \n"
SCODE &= !"} \n"

SCODE &= !"//-------------------------------------------------------------------------- \n"
SCODE &= !"// Calculate sun light... \n"
SCODE &= !"void DoLighting(inout vec3 mat, in vec3 pos, in vec3 normal, in vec3 eyeDir, in float dis) { \n"
SCODE &= !"  float h = dot(sunLight,normal); \n"
SCODE &= !"  float c = max(h, 0.0)+ambient; \n"
SCODE &= !"  mat = mat * sunColour * c ; \n"
SCODE &= !"  // Specular... \n"
SCODE &= !"  if (h > 0.0) { \n"
SCODE &= !"    vec3 R = reflect(sunLight, normal); \n"
SCODE &= !"    float specAmount = pow( max(dot(R, normalize(eyeDir)), 0.0), 3.0)*specular; \n"
SCODE &= !"    mat = mix(mat, sunColour, specAmount); \n"
SCODE &= !"  } \n"
SCODE &= !"} \n"

SCODE &= !"//-------------------------------------------------------------------------- \n"
SCODE &= !"// Hack the height, position, and normal data to create the coloured landscape \n"
SCODE &= !"vec3 TerrainColour(vec3 pos, vec3 normal, float dis){ \n"
SCODE &= !"  vec3 mat; \n"
SCODE &= !"  specular = .0; \n"
SCODE &= !"  ambient = .1; \n"
SCODE &= !"  vec3 dir = normalize(pos-cameraPos); \n"
SCODE &= !"  vec3 matPos = pos * 2.0;   // I had change scale halfway though, this lazy multiply allow me to keep the graphic scales I had \n"
SCODE &= !"  float disSqrd = dis * dis; // Squaring it gives better distance scales. \n"
SCODE &= !"  float f = clamp(Noise(matPos.xz*.05), 0.0,1.0);//*10.8; \n"
SCODE &= !"  f += Noise(matPos.xz*.1+normal.yz*1.08)*.85; \n"
SCODE &= !"  f *= .55; \n"
SCODE &= !"  vec3 m = mix(vec3(.63*f+.2, .7*f+.1, .7*f+.1), vec3(f*.43+.1, f*.3+.2, f*.35+.1), f*.65); \n"
SCODE &= !"  mat = m*vec3(f*m.x+.36, f*m.y+.30, f*m.z+.28); \n"

SCODE &= !"  // Should have used smoothstep to add colours, but left it using 'if' for sanity... \n"
SCODE &= !"  if (normal.y < .5) { \n"
SCODE &= !"    float v = normal.y; \n"
SCODE &= !"    float c = (.5-normal.y) * 4.0; \n"
SCODE &= !"    c = clamp(c*c, 0.1, 1.0); \n"
SCODE &= !"    f = Noise(vec2(matPos.x*.09, matPos.z*.095+matPos.yy*0.15)); \n"
SCODE &= !"    f += Noise(vec2(matPos.x*2.233, matPos.z*2.23))*0.5; \n"
SCODE &= !"    mat = mix(mat, vec3(.4*f), c); \n"
SCODE &= !"    specular+=.1; \n"
SCODE &= !"  } \n"

SCODE &= !"  // Grass. Use the normal to decide when to plonk grass down... \n"
SCODE &= !"  if (matPos.y < 45.35 && normal.y > .65) { \n"
SCODE &= !"    m = vec3(Noise(matPos.xz*.023)*.5+.15, Noise(matPos.xz*.03)*.6+.25, 0.0); \n"
SCODE &= !"    m *= (normal.y- 0.65)*.6; \n"
SCODE &= !"    mat = mix(mat, m, clamp((normal.y-.65)*1.3 * (45.35-matPos.y)*0.1, 0.0, 1.0)); \n"
SCODE &= !"  } \n"

SCODE &= !"  if (treeCol > 0.0) { \n"
SCODE &= !"    mat = vec3(.02+Noise(matPos.xz*5.0)*.03, .05, .0); \n"
SCODE &= !"    normal = normalize(normal+vec3(Noise(matPos.xz*33.0)*1.0-.5, .0, Noise(matPos.xz*33.0)*1.0-.5)); \n"
SCODE &= !"    specular = .0; \n"
SCODE &= !"  } \n"

SCODE &= !"  // Snow topped mountains... \n"
SCODE &= !"  if (matPos.y > 80.0 && normal.y > .42) { \n"
SCODE &= !"    float snow = clamp((matPos.y - 80.0 - Noise(matPos.xz * .1)*28.0) * 0.035, 0.0, 1.0); \n"
SCODE &= !"    mat = mix(mat, vec3(.7,.7,.8), snow); \n"
SCODE &= !"    specular += snow; \n"
SCODE &= !"    ambient+=snow *.3; \n"
SCODE &= !"  } \n"
SCODE &= !"  // Beach effect... \n"
SCODE &= !"  if (matPos.y < 1.45) { \n"
SCODE &= !"    if (normal.y > .4) { \n"
SCODE &= !"      f = Noise(matPos.xz * .084)*1.5; \n"
SCODE &= !"      f = clamp((1.45-f-matPos.y) * 1.34, 0.0, .67); \n"
SCODE &= !"      float t = (normal.y-.4); \n"
SCODE &= !"      t = (t*t); \n"
SCODE &= !"      mat = mix(mat, vec3(.09+t, .07+t, .03+t), f); \n"
SCODE &= !"    } \n"
SCODE &= !"    // Cheap under water darkening...it's wet after all... \n"
SCODE &= !"    if (matPos.y < 0.0) { \n"
SCODE &= !"      mat *= .5; \n"
SCODE &= !"    } \n"
SCODE &= !"  } \n"
SCODE &= !" \n"
SCODE &= !"  DoLighting(mat, pos, normal,dir, disSqrd); \n"
SCODE &= !"  // Do the water... \n"
SCODE &= !"  if (matPos.y < 0.0) { \n"
SCODE &= !"    // Pull back along the ray direction to get water surface point at y = 0.0 ... \n"
SCODE &= !"    float time = (iGlobalTime)*.03; \n"
SCODE &= !"    vec3 watPos = matPos; \n"
SCODE &= !"    watPos += -dir * (watPos.y/dir.y); \n"
SCODE &= !"    // Make some dodgy waves... \n"
SCODE &= !"    float tx = cos(watPos.x*.052) *4.5; \n"
SCODE &= !"    float tz = sin(watPos.z*.072) *4.5; \n"
SCODE &= !"    vec2 co = Noise2(vec2(watPos.x*4.7+1.3+tz, watPos.z*4.69+time*35.0-tx)); \n"
SCODE &= !"    co += Noise2(vec2(watPos.z*8.6+time*13.0-tx, watPos.x*8.712+tz))*.4; \n"
SCODE &= !"    vec3 nor = normalize(vec3(co.x, 20.0, co.y)); \n"
SCODE &= !"    nor = normalize(reflect(dir, nor));//normalize((-2.0*(dot(dir, nor))*nor)+dir); \n"
SCODE &= !"    // Mix it in at depth transparancy to give beach cues.. \n"
SCODE &= !"    mat = mix(mat, GetClouds(GetSky(nor)*vec3(.5,.6,1.0), nor)*.7, clamp((watPos.y-matPos.y)*.35, .2, .9)); \n"
SCODE &= !"    // Add some extra water glint... \n"
SCODE &= !"    float sunAmount = max( dot(nor, sunLight), 0.0 ); \n"
SCODE &= !"    mat = mat + sunColour * pow(sunAmount, 228.5)*.6; \n"
SCODE &= !"  } \n"
SCODE &= !"  mat = ApplyFog(mat, disSqrd, dir); \n"
SCODE &= !"  return mat; \n"
SCODE &= !"} \n"

SCODE &= !"//-------------------------------------------------------------------------- \n"
SCODE &= !"float BinarySubdivision(in vec3 rO, in vec3 rD, vec2 t) { \n"
SCODE &= !"  // Home in on the surface by dividing by two and split... \n"
SCODE &= !"  float halfwayT; \n"
SCODE &= !"  for (int n = 0; n < 4; n++) { \n"
SCODE &= !"    halfwayT = (t.x + t.y) * .5; \n"
SCODE &= !"    vec3 p = rO + halfwayT*rD; \n"
SCODE &= !"    if (Map(p) < 0.5) { \n"
SCODE &= !"      t.x = halfwayT; \n"
SCODE &= !"    } else { \n"
SCODE &= !"      t.y = halfwayT; \n"
SCODE &= !"    } \n"
SCODE &= !"  } \n"
SCODE &= !"  return t.x; \n"
SCODE &= !"} \n"

SCODE &= !"//-------------------------------------------------------------------------- \n"
SCODE &= !"bool Scene(in vec3 rO, in vec3 rD, out float resT, in vec2 fragCoord) { \n"
SCODE &= !"  float t = 1.2 + Hash12(fragCoord.xy); \n"
SCODE &= !"  float oldT = 0.0; \n"
SCODE &= !"  float delta = 0.0; \n"
SCODE &= !"  bool fin = false; \n"
SCODE &= !"  bool res = false; \n"
SCODE &= !"  vec2 distances; \n"
SCODE &= !"  for( int j=0; j<150; j++ ) {\n"
SCODE &= !"    if (t>150.0) break; // !!! t>240,0 \n"
SCODE &= !"    vec3 p = rO + t*rD; \n"
SCODE &= !"    float h = Map(p); // ...Get this positions height mapping. \n"
SCODE &= !"    // Are we inside, and close enough to fudge a hit?... \n"
SCODE &= !"    if( h < 0.5) { \n"
SCODE &= !"      fin = true; \n"
SCODE &= !"      distances = vec2(t, oldT); \n"
SCODE &= !"      break; \n"
SCODE &= !"    } \n"
SCODE &= !"    // Delta ray advance - a fudge between the height returned and the distance already travelled. \n"
SCODE &= !"    // It's a really fiddly compromise between speed and accuracy \n"
SCODE &= !"    // Too large a step and the tops of ridges get missed. \n"
SCODE &= !"    delta = max(0.01, 0.3*h) + (t*0.0065); \n"
SCODE &= !"    oldT = t; \n"
SCODE &= !"    t += delta; \n"
SCODE &= !"  } \n"
SCODE &= !"  if (fin) resT = BinarySubdivision(rO, rD, distances); \n"
SCODE &= !"  return fin; \n"
SCODE &= !"} \n"

SCODE &= !"//-------------------------------------------------------------------------- \n"
SCODE &= !"vec3 CameraPath( float t ) \n"
SCODE &= !"{ \n"
SCODE &= !"  float m = 1.0+(iMouse.x/iResolution.x)*300.0; \n"
SCODE &= !"  t = (iGlobalTime*1.5+m+657.0)*.006 + t; \n"
SCODE &= !"    vec2 p = 476.0*vec2( sin(3.5*t), cos(1.5*t) ); \n"
SCODE &= !"  return vec3(335.0-p.x, 0.6, 308.0+p.y); \n"
SCODE &= !"} \n"
SCODE &= !"// Some would say, most of the magic is done in post! :D \n"

SCODE &= !"vec3 PostEffects(in vec3 rgb, in vec2 uv) { \n"
SCODE &= !"  vec3 c = (1.0 - exp(-rgb * 6.0)) * 1.0024; \n"
SCODE &= !"  return c; \n"
SCODE &= !"} \n"

SCODE &= !"void mainImage( out vec4 fragColor, in vec2 fragCoord) { \n"
SCODE &= !"  vec2 xy = -1.0 + 2.0*fragCoord.xy / iResolution.xy; \n"
SCODE &= !"  vec2 uv = xy * vec2(iResolution.x/iResolution.y,1.0); \n"
SCODE &= !"  vec3 camTar; \n"
SCODE &= !"  #ifdef STEREO \n"
SCODE &= !"  float isCyan = mod(fragCoord.x + mod(fragCoord.y,2.0),2.0); \n"
SCODE &= !"  #endif \n"
SCODE &= !"  // Use several forward heights, of decreasing influence with distance from the camera. \n"
SCODE &= !"  float h = 0.0; \n"
SCODE &= !"  float f = 1.0; \n"
SCODE &= !"  for (int i = 0; i < 7; i++) { \n"
SCODE &= !"    h += Terrain(CameraPath((.6-f)*.008).xz) * f; \n"
SCODE &= !"    f -= .1; \n"
SCODE &= !"  } \n"
SCODE &= !"  cameraPos.xz = CameraPath(0.0).xz; \n"
SCODE &= !"  camTar.xz   = CameraPath(.005).xz; \n"
SCODE &= !"  camTar.y = cameraPos.y = max((h*.25)+3.5, 1.0); \n"
SCODE &= !"  float roll = 0.15*sin(iGlobalTime*.2); \n"
SCODE &= !"  vec3 cw = normalize(camTar-cameraPos); \n"
SCODE &= !"  vec3 cp = vec3(sin(roll), cos(roll),0.0); \n"
SCODE &= !"  vec3 cu = normalize(cross(cw,cp)); \n"
SCODE &= !"  vec3 cv = normalize(cross(cu,cw)); \n"
SCODE &= !"  vec3 rd = normalize( uv.x*cu + uv.y*cv + 1.5*cw ); \n"
SCODE &= !"  #ifdef STEREO \n"
SCODE &= !"  cameraPos += .45*cu*isCyan; // move camera to the right - the rd vector is still good \n"
SCODE &= !"  #endif \n"
SCODE &= !"  vec3 col; \n"
SCODE &= !"  float distance; \n"
SCODE &= !"  if(!Scene(cameraPos,rd, distance, fragCoord)) { \n"
SCODE &= !"    // Missed scene, now just get the sky value... \n"
SCODE &= !"    col = GetSky(rd); \n"
SCODE &= !"    col = GetClouds(col, rd); \n"
SCODE &= !"  } \n"
SCODE &= !"  else \n"
SCODE &= !"  { \n"
SCODE &= !"    // Get world coordinate of landscape... \n"
SCODE &= !"    vec3 pos = cameraPos + distance * rd; \n"
SCODE &= !"    // Get normal from sampling the high definition height map \n"
SCODE &= !"    // Use the distance to sample larger gaps to help stop aliasing... \n"
SCODE &= !"    float p = min(.3, .0005+.00005 * distance*distance); \n"
SCODE &= !"    vec3 nor =     vec3(0.0, Terrain2(pos.xz             ), 0.0); \n"
SCODE &= !"    vec3 v2  = nor-vec3(p  , Terrain2(pos.xz+vec2(p,0.0 )), 0.0); \n"
SCODE &= !"    vec3 v3  = nor-vec3(0.0, Terrain2(pos.xz+vec2(0.0,-p)), -p); \n"
SCODE &= !"    nor = cross(v2, v3); \n"
SCODE &= !"    nor = normalize(nor); \n"
SCODE &= !"    // Get the colour using all available data... \n"
SCODE &= !"    col = TerrainColour(pos, nor, distance); \n"
SCODE &= !"  } \n"
SCODE &= !"  // PostEffects \n"
SCODE &= !"  col = (1.0 - exp(-col * 6.0)) * 1.024; \n"
SCODE &= !"  #ifdef STEREO   \n"
SCODE &= !"  col *= vec3( isCyan, 1.0-isCyan, 1.0-isCyan );   \n"
SCODE &= !"  #endif \n"
SCODE &= !"  fragColor=vec4(col,1.0); \n"
SCODE &= !"} \n"
SCODE &= !"//-------------------------------------------------------------------------- \n"


#include once "fbgfx.bi"
#include once "GL/gl.bi"
#include once "GL/glext.bi"

#ifndef NULL
#define NULL 0
#endif


type vec3
  as GLfloat x,y,z
end type

sub ErrorExit(msg as string)
  if screenptr() then screen 0
  dim as integer w,h
  screeninfo w,h : w*=0.75:h*=0.75
  screenres w,h
  print msg
  print "press any key to quit ..."
  beep : sleep : end 1
end sub

' define OpenGL proc's
#define glDefine(n) dim shared as PFN##n##PROC n
' texture
'  glDefine(glActiveTexture)
' shader
glDefine(glCreateShader)
glDefine(glDeleteShader)
glDefine(glShaderSource)
glDefine(glCompileShader)
glDefine(glGetShaderiv)
glDefine(glGetShaderInfoLog)
' program
glDefine(glCreateProgram)
glDefine(glDeleteProgram)
glDefine(glAttachShader)
glDefine(glDetachShader)
glDefine(glLinkProgram)
glDefine(glGetProgramiv)
glDefine(glGetProgramInfoLog)
glDefine(glUseProgram)
' uniform
glDefine(glGetUniformLocation)
glDefine(glUniform1f)
glDefine(glUniform2f)
glDefine(glUniform3f)
glDefine(glUniform4f)
glDefine(glUniform1i)
#undef glDefine

sub glScreen(w as integer=640, h as integer=360, b as integer=32, d as integer=24, s as integer=0, f as integer=0)
  if ScreenPtr() then screen 0
  ScreenControl FB.SET_GL_STENCIL_BITS,s
  ScreenControl FB.SET_GL_DEPTH_BITS  ,d
  if ScreenRes(w,h,b,,FB.GFX_OPENGL or iif(f<>0,FB.GFX_FULLSCREEN,0)) then
    ErrorExit("screenres(" & w & "," & h &") failed !")
  end if
  Windowtitle "offline shadertoy.com"

  flip
  ' get OpenGL proc's (abort if something goes wrong)
  #define glProc(n) n = ScreenGLProc(#n) : if n = 0 then ErrorExit(#n)
  ' texture
  '  glProc(glActiveTexture)
  ' shader
  glProc(glCreateShader)
  glProc(glDeleteShader)
  glProc(glShaderSource)
  glProc(glCompileShader)
  glProc(glGetShaderiv)
  glProc(glGetShaderInfoLog)
  ' program
  glProc(glCreateProgram)
  glProc(glDeleteProgram)
  glProc(glAttachShader)
  glProc(glDetachShader)
  glProc(glLinkProgram)
  glProc(glGetProgramiv)
  glProc(glGetProgramInfoLog)
  glProc(glUseProgram)
  ' uniform
  glProc(glGetUniformLocation)
  glProc(glUniform1f)
  glProc(glUniform2f)
  glProc(glUniform3f)
  glProc(glUniform4f)
  glProc(glUniform1i)
  #undef glProc
end sub

type ShaderToy
  declare destructor
  declare function CompileFile(Filename as string) as boolean
  declare function CompileCode(Code as string) as boolean
  as GLuint FragmentShader
  as GLuint ProgramObject
  as string Shaderlog
end type
destructor ShaderToy
  if ProgramObject then 
   glUseprogram(0)
   if FragmentShader  then 
     glDetachShader(ProgramObject,FragmentShader)
     glDeleteShader(FragmentShader)
   end if
   glDeleteProgram(ProgramObject)
  end if
end destructor

function ShaderToy.CompileFile(filename as string) as boolean
  dim as string code
  var hFile = FreeFile()
  if open(filename,for input, as #hFile) then 
    ShaderLog = "can't read shader: " & chr(34) & filename  & chr(34) & " !"
    return false
  end if
  while not eof(hFile)
    dim as string aLine
    line input #hFile,aLine
    code &= aLine & !"\n"
  wend
  close #hFile
  return CompileCode(code)
end function

function ShaderToy.CompileCode(UserCode as string) as boolean
  dim as GLint logSize
  dim as GLint status
  dim as string FragmentProlog
  FragmentProlog & =!"uniform float     iGlobalTime;  // shader playback time (in seconds)\n"
  FragmentProlog & =!"uniform vec3      iResolution;  // viewport resolution (in pixels)\n"
  FragmentProlog & =!"uniform vec4      iMouse;       // mouse pixel coords. xy: current (if MLB down), zw: click\n"
  FragmentProlog & =!"uniform vec4      iDate;        // (year, month, day, time in seconds)\n"
  FragmentProlog & =!"uniform sampler2D iChannel0;\n"
  FragmentProlog & =!"uniform sampler2D iChannel1;\n"
  FragmentProlog & =!"uniform sampler2D iChannel2;\n"
  FragmentProlog & =!"uniform sampler2D iChannel3;\n"
  dim as string FragmentEpilog
  FragmentEpilog &= !"void main() {\n"
  FragmentEpilog &= !"  vec4 color;\n"
  FragmentEpilog &= !"  // call user shader\n"
  FragmentEpilog &= !"  mainImage(color, gl_FragCoord.xy);\n"
  FragmentEpilog &= !"  color.w = 1.0;\n"
  FragmentEpilog &= !"  gl_FragColor = color;\n"
  FragmentEpilog &= !"}\n"

  dim as string FragmentCode = FragmentProlog & UserCode & FragmentEpilog

  FragmentShader = glCreateShader(GL_FRAGMENT_SHADER)
  if FragmentShader=0 then 
    ShaderLog = "glCreateShader(GL_FRAGMENT_SHADER) failed !"
    return false
  end if
  dim as GLchar ptr pCode=strptr(FragmentCode)
  glShaderSource (FragmentShader, 1, @pCode, NULL)
  glCompileShader(FragmentShader)
  glGetShaderiv  (FragmentShader, GL_COMPILE_STATUS, @status)
  if status = GL_FALSE then 
    glGetShaderiv(FragmentShader, GL_INFO_LOG_LENGTH, @logSize)
    ShaderLog = space(logSize)
    glGetShaderInfoLog(FragmentShader, logSize, NULL, cptr(GLchar ptr,strptr(ShaderLog)) )
    ShaderLog = !"glCompileShader(FragmentShader) failed !\n" & Shaderlog
    glDeleteShader(FragmentShader) : FragmentShader = 0
    return false
  end if

  ProgramObject = glCreateProgram()
  if ProgramObject=0 then 
    ShaderLog = "glCreateProgram() failed !"
    glDeleteShader(FragmentShader) : FragmentShader = 0
    return false
  end if
  glAttachShader(ProgramObject,FragmentShader)
  glLinkProgram (ProgramObject)
  glGetProgramiv(ProgramObject, GL_LINK_STATUS, @status)
  if (status = GL_FALSE) then
    glGetProgramiv(ProgramObject, GL_INFO_LOG_LENGTH, @logSize)
    ShaderLog = space(logSize)
    glGetProgramInfoLog (ProgramObject, logSize, NULL, cptr(GLchar ptr,strptr(ShaderLog)) )
    ShaderLog = !"glLinkProgram() failed !\n" & Shaderlog
    glDeleteShader(FragmentShader) : FragmentShader = 0
    return false
  end if
  return true
end function

'
' main
'


' init Screenres, create the OpenGL context and load some OpenGL procs.
dim as integer pixels=640
' wide screen 16:9
glScreen pixels,pixels/16*9


' get curent resolution
dim as integer scr_w,scr_h
screeninfo scr_w,scr_h

dim as vec3 v3
v3.x=scr_w     ' width in pixle
v3.y=scr_h     '`height in pixle
v3.z=v3.x/v3.y ' pixel ratio

dim as ShaderToy Shader

if Shader.CompileCode(SCODE)=false then
  ErrorExit Shader.ShaderLog
end if  

' enable shader
glUseProgram(Shader.ProgramObject)

' get uniforms locations in shader program
var iGlobalTime = glGetUniformLocation(Shader.ProgramObject,"iGlobalTime")
var iResolution = glGetUniformLocation(Shader.ProgramObject,"iResolution")
var iMouse      = glGetUniformLocation(Shader.ProgramObject,"iMouse")

' set vec3 iResolution
glUniform3f(iResolution,v3.x,v3.y,v3.z)

dim as integer mx,my,mb,frames,fps
dim as double tStart = Timer()
dim as double tLast=tStart
while inkey=""
  dim as double tNow=Timer()-tStart
  ' set uniform float iGlobalTime
  glUniform1f(iGlobalTime,tNow)

  if frames mod 3=0 then
    ' set vec4 iMouse
    if getMouse(mx,my,,mb)=0 then
      if mb then
        glUniform4f(iResolution,mx,scr_h-my,1,1)
      else
        glUniform4f(iResolution,0,0,0,0)
      end if
    end if
  end if


  'glClear(GL_COLOR_BUFFER_BIT)

  ' draw a rectangle (2 triangles over the whole screen)
  glRectf(-1,-1,1,1)
  flip ' swap the buffers

  frames+=1
  ' update fps
  if frames mod 24=0 then
    fps=24/(tNow-tLast)
    windowtitle "fps: " & fps
    tLast=tNow
  end if

wend

' disable shader
glUseProgram(0)
Last edited by D.J.Peters on Aug 31, 2016 12:47, edited 2 times in total.
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Can you post your FPS result please ?

Post by srvaldez »

on my Mac I get a steady 60 fps but I had to comment-out lines 419 and 458 --duplicate definition of glDefine(glActiveTexture) and lines 626 thru 635 as fb on mac has no mouse lib yet.

on my virtual machine running Windows 10 x64, compiled with FBx64-gen gcc -Wc -O3
the fps vary between 70 and 200+
my PC is a Mac Pro mid 2010 with 48GB RAM and NVIDIA Quadro K5000 video card
Imortis
Moderator
Posts: 1923
Joined: Jun 02, 2005 15:10
Location: USA
Contact:

Re: Can you post your FPS result please ?

Post by Imortis »

I get anywhere between 90 and (rarely) 290 FPS.
St_W
Posts: 1619
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Can you post your FPS result please ?

Post by St_W »

I get only about 5 fps in both the FB application as well as the web app, but it rather feels like < 2 fps.

GeForce 8600 GT
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Can you post your FPS result please ?

Post by srvaldez »

Imortis wrote:I get anywhere between 90 and (rarely) 290 FPS.
was that in a VM ?, my observation is that fps in a VM are not reliable in this case, also what's your hardware specs.
btw, I had no idea about the GLSL language, looks very much like C, wonder if you could use it for things other than graphics.
Imortis
Moderator
Posts: 1923
Joined: Jun 02, 2005 15:10
Location: USA
Contact:

Re: Can you post your FPS result please ?

Post by Imortis »

Nope. That is real hardware.

CPU: AMD FX-8230E Eight Core 3.20ghz
RAM: 16GB
GPU: AMD Radeon R9 200 series
OS: 64bit Windows 7
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Can you post your FPS result please ?

Post by srvaldez »

@ Imortis
it's possible then that the erratic fps behavior is specific to Windows, I will try in Ubuntu and see.
[edit] Ubuntu in a VM fps is erratic also.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Can you post your FPS result please ?

Post by caseih »

On 64-bit Linux with 1.05 I was unable to compile the program at all:

Code: Select all

/tmp/shadertest.bas(419) error 4: Duplicated definition, glActiveTexture in 'glDefine(glActiveTexture)'
/tmp/shadertest.bas(458) error 316: Function result assignment outside of the function, found '=' in 'glProc(glActiveTexture)'
/tmp/shadertest.bas(458) error 1: Argument count mismatch, found '=' in 'glProc(glActiveTexture)'
Not sure if the forum software messed up the code and it didn't copy and paste right, or what.
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Can you post your FPS result please ?

Post by srvaldez »

just comment-out lines 419 and 458
Imortis
Moderator
Posts: 1923
Joined: Jun 02, 2005 15:10
Location: USA
Contact:

Re: Can you post your FPS result please ?

Post by Imortis »

srvaldez wrote:@ Imortis
it's possible then that the erratic fps behavior is specific to Windows, I will try in Ubuntu and see.
[edit] Ubuntu in a VM fps is erratic also.
The FPS stayed at 90 most of the time, but when it would get really close to the surface or really far way from everything, the FPS would spike.

It looks to me like it was getting higher when there was less on the screen to draw. I don't think that is unexpected.

BTW: Tried it on a machine with crappy onboard GPU and got 0 to 5 FPS. 0 I am assuming is a decimal rounded down. It also slowed everything down on this machine. Same as before, though. 5 FPS was when I got really close to surfaces or far away from everything.
leopardpm
Posts: 1795
Joined: Feb 28, 2009 20:58

Re: Can you post your FPS result please ?

Post by leopardpm »

with code as is, I get 3-5 fps on my low-end laptop. No idea how to use webGL...
Zippy
Posts: 1295
Joined: Feb 10, 2006 18:05

Re: Can you post your FPS result please ?

Post by Zippy »

27-60fps
::average 30fps w/dense imagery
nVidia GeForce GT 720
GPU Temp rise to 135F from 88F, w/68F ambient

i7-4790 CPU @ 3.60GHz
::CPU usage 10-14%, average 12%
::frequency rise to 110%

RAM usage 18.2MB
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Can you post your FPS result please ?

Post by srvaldez »

leopardpm wrote:with code as is, I get 3-5 fps on my low-end laptop. No idea how to use webGL...
try going to this website https://www.shadertoy.com/view/4slGD4 I think that's what they mean.
I get about 59 to 60 fps.
btw, I think getting more than 60 fps is a bug in OpenGL in windows and Linux.
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Can you post your FPS result please ?

Post by srvaldez »

here's the Winding Menger Tunnel

Code: Select all

dim as string SCODE
SCODE &= !"/* \n"
SCODE &= !" \n"
SCODE &= !"	Winding Menger Tunnel \n"
SCODE &= !"	--------------------- \n"
SCODE &= !" \n"
SCODE &= !"	I got bored and decided to wrap a Menger object around a curvy tunnel, then I got even more bored and  \n"
SCODE &= !"	incorporated some tubing and some curved screens... I have no idea what they're for either. :) \n"
SCODE &= !" \n"
SCODE &= !"	Anyway, if you put aside the cheesy, Quake-2-style graphics, it's nothing more than a couple of  \n"
SCODE &= !"	interwoven fractal objects perturbed sinusoidally about the ""XY"" plane. In code: \n"
SCODE &= !" \n"
SCODE &= !"	pos.xy -= sinPath(pos.z); \n"
SCODE &= !"	dist = FractalObjects(pos); \n"
SCODE &= !" \n"
SCODE &= !"	Obviously, the camera has to follow the path as well, but that's basically it. You can ignore everything  \n"
SCODE &= !"	else, which is just less-than-adequate window dressing. I've been on a bit of an oldschool demo trip  \n"
SCODE &= !"	lately, which probably explains the simplistic lighting style. \n"
SCODE &= !" \n"
SCODE &= !"	Other tunnel related examples worth looking at: \n"
SCODE &= !" \n"
SCODE &= !"	// Awesome example. Makes the lighting effort in this one look lazy... which it is. :) \n"
SCODE &= !"    Castle Tunnel - Hamneggs \n"
SCODE &= !"    https://www.shadertoy.com/view/Xs3Xzn \n"
SCODE &= !" \n"
SCODE &= !"    // Love this. It inspired me to interweave the metal tubing in this particular shader. \n"
SCODE &= !"    Metro Tunnel - fb39ca4 \n"
SCODE &= !"    https://www.shadertoy.com/view/ldsGRS \n"
SCODE &= !" \n"
SCODE &= !"    // Like all of dr2's stuff, it has a higher level of difficulty. :) \n"
SCODE &= !"    Gotthard Tunnel - dr2 \n"
SCODE &= !"    https://www.shadertoy.com/view/MlSXRR  \n"
SCODE &= !" \n"
SCODE &= !"*/ \n"
SCODE &= !" \n"
SCODE &= !" \n"
SCODE &= !"// Used to identify individual scene objects. In this case, there are only three: The metal framework, the walls, \n"
SCODE &= !"// and the lights. \n"
SCODE &= !"float objID = 0.; // Metal = 1., Walls = 2., Screens = 3.. \n"
SCODE &= !" \n"
SCODE &= !"// Simple hash function. \n"
SCODE &= !"float hash( float n ){ return fract(cos(n)*45758.5453); } \n"
SCODE &= !" \n"
SCODE &= !" \n"
SCODE &= !"// Tri-Planar blending function. Based on an old Nvidia writeup: \n"
SCODE &= !"// GPU Gems 3 - Ryan Geiss: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch01.html \n"
SCODE &= !"vec3 tex3D( sampler2D tex, in vec3 p, in vec3 n ){ \n"
SCODE &= !"    \n"
SCODE &= !"    n = max(abs(n), 0.001); // n = max((abs(n) - 0.2)*7., 0.001); // n = max(abs(n), 0.001), etc. \n"
SCODE &= !"    n /= (n.x + n.y + n.z);  \n"
SCODE &= !"	return (texture2D(tex, p.yz)*n.x + texture2D(tex, p.zx)*n.y + texture2D(tex, p.xy)*n.z).xyz; \n"
SCODE &= !"     \n"
SCODE &= !"} \n"
SCODE &= !" \n"
SCODE &= !"// Common formula for rounded squares, for all intended purposes. \n"
SCODE &= !"float lengthN(in vec2 p, in float n){ p = pow(abs(p), vec2(n)); return pow(p.x + p.y, 1.0/n); } \n"
SCODE &= !" \n"
SCODE &= !"// 2D path displacement. \n"
SCODE &= !"vec2 path(in float x){ \n"
SCODE &= !"     \n"
SCODE &= !"    //return vec2(0); // Trivial, straight path. \n"
SCODE &= !"    //return vec2(cos(x*0.25)*1.8 + cos(x*0.15)*2., 0); // Perturbing ""X"" only. \n"
SCODE &= !"    return vec2(cos(x*0.25)*1.8 + cos(x*0.15)*1.5, sin(x*0.25)*1.2 + sin(x*0.15)); // Perturbing ""X"" and ""Y."" \n"
SCODE &= !"     \n"
SCODE &= !"     \n"
SCODE &= !"} \n"
SCODE &= !" \n"
SCODE &= !"// Camera path. Arranged to coincide with the frequency of the tunnel. \n"
SCODE &= !"vec3 camPath(float t){ \n"
SCODE &= !"   \n"
SCODE &= !"    return vec3(path(t), t); \n"
SCODE &= !"     \n"
SCODE &= !"} \n"
SCODE &= !" \n"
SCODE &= !"// Smooth minimum function. There are countless articles, but IQ explains it best here: \n"
SCODE &= !"// http://iquilezles.org/www/articles/smin/smin.htm \n"
SCODE &= !"float sminP( float a, float b, float s ){ \n"
SCODE &= !" \n"
SCODE &= !"    float h = clamp( 0.5+0.5*(b-a)/s, 0.0, 1.0 ); \n"
SCODE &= !"    return mix( b, a, h ) - s*h*(1.0-h); \n"
SCODE &= !"} \n"
SCODE &= !" \n"
SCODE &= !"// I have a ""Menger Sponge Variation"" example somewhere, if you'd like to look into this. \n"
SCODE &= !"float Menger(in vec3 q){ \n"
SCODE &= !"     \n"
SCODE &= !"    float s = 4.; \n"
SCODE &= !"    // Layer one. The "".05"" on the end varies the hole size. \n"
SCODE &= !" 	vec3 p = abs(fract(q/s)*s - s*.5); \n"
SCODE &= !" 	float d = min(max(p.x, p.y), min(max(p.y, p.z), max(p.x, p.z))) - s/3.;// + .05; \n"
SCODE &= !"     \n"
SCODE &= !"    s /= 2.; \n"
SCODE &= !"    // Layer two. \n"
SCODE &= !"    p = abs(fract(q/s)*s - s*.5); \n"
SCODE &= !" 	d = max(d, min(max(p.x, p.y), min(max(p.y, p.z), max(p.x, p.z))) - s/3.);//+ .05 \n"
SCODE &= !"    \n"
SCODE &= !"    s /= 3.; \n"
SCODE &= !"    // Layer three. 3D space is divided by two, instead of three, to give some variance. \n"
SCODE &= !"    p = abs(fract(q/s)*s - s*.5); \n"
SCODE &= !" 	d = max(d, min(max(p.x, p.y), min(max(p.y, p.z), max(p.x, p.z))) - s/3.); //- .015  \n"
SCODE &= !"     \n"
SCODE &= !"     \n"
SCODE &= !"    //float floor = max(abs(q.x) - 2., abs(q.y) - 1.5);//abs(q.x) - 2.;// \n"
SCODE &= !"    //return q.y + .8; \n"
SCODE &= !"    return min(d, q.y + .8); \n"
SCODE &= !"  \n"
SCODE &= !"} \n"
SCODE &= !" \n"
SCODE &= !"// I have a ""Steel Lattice"" example somewhere, if you'd like to look into this. There's not \n"
SCODE &= !"// much to it, though. \n"
SCODE &= !"float tubing(in vec3 p){ \n"
SCODE &= !"  \n"
SCODE &= !"    // SECTION 1 \n"
SCODE &= !"    // \n"
SCODE &= !"    // Repeat field entity one, which is just some tubes repeated in all directions every  \n"
SCODE &= !"    // two units, then combined with a smooth minimum function. Otherwise known as a lattice. \n"
SCODE &= !"    p = fract(p/2.)*2. - 1.; \n"
SCODE &= !"    float x1 = sminP(length(p.xy),sminP(length(p.yz),length(p.xz), 0.25), 0.25)-0.5; // EQN 1 \n"
SCODE &= !"    //float x1 = sqrt(min(dot(p.xy, p.xy),min(dot(p.yz, p.yz),dot(p.xz, p.xz))))-0.5; // EQN 2 \n"
SCODE &= !"    //p = abs(p); float x1 = min(max(p.x, p.y),min(max(p.y, p.z),max(p.x, p.z)))-0.5; // EQN 3 \n"
SCODE &= !" \n"
SCODE &= !"    // SECTION 2 \n"
SCODE &= !"    // \n"
SCODE &= !"    // Repeat field entity two, which is just an abstract object repeated every half unit.  \n"
SCODE &= !"    p = abs(fract(p*2.)*.5 - .25); \n"
SCODE &= !"    //float x2 = min(p.x,min(p.y,p.z)); // EQN 1 \n"
SCODE &= !"    //float x2 = min(max(p.x, p.y),min(max(p.y, p.z),max(p.x, p.z)))-0.15; //-0.175, etc. // EQN 2 \n"
SCODE &= !"    float x2 = min(p.x, min(p.y,p.z))-.025; // EQN 1 \n"
SCODE &= !"     \n"
SCODE &= !"    // SECTION 3 \n"
SCODE &= !"    // \n"
SCODE &= !"    // Combining the two entities above. \n"
SCODE &= !"    return max(abs(x1), abs(x2)) - .0175; \n"
SCODE &= !"     \n"
SCODE &= !"} \n"
SCODE &= !" \n"
SCODE &= !"// Creating the scene geometry. This is the process: \n"
SCODE &= !"// \n"
SCODE &= !"// Use the sinusoidal path function to perturb the original position. Create the Menger object \n"
SCODE &= !"// using the perturbed postion. Do the same for the tubing and again with the screens. \n"
SCODE &= !"// Return the minimum of the objects, and also use the relative minimums to return the object's \n"
SCODE &= !"// individual ID. That's basically it. \n"
SCODE &= !"float map(in vec3 p){ \n"
SCODE &= !"    \n"
SCODE &= !" \n"
SCODE &= !"	// Partial anti-warping solution, based on Gaz's ""Square Sin Curve"" shader below: \n"
SCODE &= !"    // https://www.shadertoy.com/view/MscGzf \n"
SCODE &= !"    // \n"
SCODE &= !"    // As you could imagine, tunnels (columns) get a little warped when you bend them. Countering  \n"
SCODE &= !"    // that by taking the curvature into account helps quite a bit. Unfortunately, it slows things  \n"
SCODE &= !"    // down, so isn't being used here, which is a shame, because I like it a lot more. Anyway, if  \n"
SCODE &= !"    // you can spare the cycles, it gives the tunnel's ""X"" and ""Y"" (width and height) dimensions a  \n"
SCODE &= !"    // little more consistency. \n"
SCODE &= !"    //vec2 g = (path(p.z + 0.01) - path(p.z - 0.01))/0.02; \n"
SCODE &= !"    //g = cos(atan(g)); \n"
SCODE &= !"     \n"
SCODE &= !"     \n"
SCODE &= !"    // ""Windy Tunnels 101"" - Use ""Z"" to perturb the ""XY"" plane. If you're not sure how it'd done, \n"
SCODE &= !"    // I have a few tunnel examples where I explain the process. \n"
SCODE &= !"    p.xy -= path(p.z); \n"
SCODE &= !"     \n"
SCODE &= !"    //p.xy *= g; // See the anti-warping explanation above. \n"
SCODE &= !" \n"
SCODE &= !" \n"
SCODE &= !"    // A bit of tubing, using a combination of repeat objects. \n"
SCODE &= !"    float tube = tubing(p); \n"
SCODE &= !"     \n"
SCODE &= !"     \n"
SCODE &= !"    // Again a little expensive, but it's a surprisingly effective way to bump the tunnel walls. \n"
SCODE &= !"    // This is a variation, but you can thank ""aeikick"" for this little snippet. :) \n"
SCODE &= !"    //vec3 u = p; \n"
SCODE &= !"    //p.x -= sign(u.x)*(texture2D(iChannel0, u.yz/8.).x - .0)*.03;//-.2; \n"
SCODE &= !"	//p.y -= sign(u.y)*(texture2D(iChannel0, u.xz/8.).x - .0)*.03;   \n"
SCODE &= !" \n"
SCODE &= !"     \n"
SCODE &= !"    // The walls. I have another Menger example, if you'd like to look into that more closely. \n"
SCODE &= !"    float walls = Menger(p); \n"
SCODE &= !"    // Simpler alternatives. \n"
SCODE &= !"    //float walls = 1. - max(abs(p.x), abs(p.y)); \n"
SCODE &= !"    //float walls = 1.25 - lengthN(p.xy, 4.0); \n"
SCODE &= !"     \n"
SCODE &= !"    // The curved screens. Kind of worth the effort, but not really. Fine details always overcomplicate  \n"
SCODE &= !"    // things, not to mention, halve the frame rate. :) Anyway, it's basically repeated square box-related  \n"
SCODE &= !"    // stuff... Add this, take that, etc. Fiddly, hacky, not all that interesting, and probably not the \n"
SCODE &= !"    // best way to do it. Chipping away at a cylinder might raymarch better.  \n"
SCODE &= !"    // \n"
SCODE &= !"    p += vec3(sign(p.x)*(-.11 + (sin(p.z*3.14159*2. + 1.57/1.))*.05), 0., 0.); // Screen curve, and repositioning. \n"
SCODE &= !"    vec3 q = abs(mod(p + vec3(.0, .5, 0.), vec3(1., 1., 2.)) - vec3(.5, .5, 1.)); // Repeat space. \n"
SCODE &= !"    float light = max(max(q.y, q.z) - .22, q.x-.05); // Box. \n"
SCODE &= !"    light = max(light, max(abs(p.x) - .5, abs(p.y) - .22)); // Chopping off anything outside the tunnel... Kind of. \n"
SCODE &= !"     \n"
SCODE &= !"    // Object ID: Equivalent to: if(tube<walls)objID=2; else objID = 1.; //etc. \n"
SCODE &= !"    // \n"
SCODE &= !"    // By the way, if you need to identify multiple objects, you're better off doing it in a seperate pass,  \n"
SCODE &= !"    // after the raymarching function. Having multiple ""if"" statements in a distance field equation can  \n"
SCODE &= !"    // slow things down considerably. \n"
SCODE &= !"    objID = step(tube, light) + step(tube, walls) + step(light, tube)*step(light, walls)*3.; \n"
SCODE &= !"    \n"
SCODE &= !" \n"
SCODE &= !"    // Returning the minimum of the three objects. \n"
SCODE &= !"    return min(min(tube, walls), light); \n"
SCODE &= !"} \n"
SCODE &= !" \n"
SCODE &= !" \n"
SCODE &= !" \n"
SCODE &= !"// Tetrahedral normal, to save a couple of ""map"" calls. Courtesy of IQ. \n"
SCODE &= !"vec3 calcNormal(in vec3 p){ \n"
SCODE &= !" \n"
SCODE &= !"    // Note the slightly increased sampling distance, to alleviate artifacts due to hit point inaccuracies. \n"
SCODE &= !"    vec2 e = vec2(0.0025, -0.0025);  \n"
SCODE &= !"    return normalize(e.xyy * map(p + e.xyy) + e.yyx * map(p + e.yyx) + e.yxy * map(p + e.yxy) + e.xxx * map(p + e.xxx)); \n"
SCODE &= !"} \n"
SCODE &= !" \n"
SCODE &= !"/* \n"
SCODE &= !"// Standard normal function. \n"
SCODE &= !"vec3 calcNormal(in vec3 p) { \n"
SCODE &= !"	const vec2 e = vec2(0.005, 0); \n"
SCODE &= !"	return normalize(vec3(map(p + e.xyy) - map(p - e.xyy), map(p + e.yxy) - map(p - e.yxy),	map(p + e.yyx) - map(p - e.yyx))); \n"
SCODE &= !"} \n"
SCODE &= !"*/ \n"
SCODE &= !" \n"
SCODE &= !" \n"
SCODE &= !"float calcAO(in vec3 pos, in vec3 nor) \n"
SCODE &= !"{ \n"
SCODE &= !"	float sca = 2., occ = 0.0; \n"
SCODE &= !"    for( int i=0; i<5; i++ ){ \n"
SCODE &= !"     \n"
SCODE &= !"        float hr = 0.01 + float(i)*0.5/4.0;         \n"
SCODE &= !"        float dd = map( nor * hr + pos ); \n"
SCODE &= !"        occ += (hr - dd)*sca; \n"
SCODE &= !"        sca *= 0.7; \n"
SCODE &= !"    } \n"
SCODE &= !"    return clamp( 1.0 - occ, 0.0, 1.0 );     \n"
SCODE &= !"} \n"
SCODE &= !" \n"
SCODE &= !" \n"
SCODE &= !"// Texture bump mapping. Four tri-planar lookups, or 12 texture lookups in total. \n"
SCODE &= !"// I tried to make it as concise as possible. Whether that translate to speed, or not, \n"
SCODE &= !"// I couldn't say. \n"
SCODE &= !"vec3 texBump( sampler2D tx, in vec3 p, in vec3 n, float bf){ \n"
SCODE &= !"    \n"
SCODE &= !"    const vec2 e = vec2(0.002, 0); \n"
SCODE &= !"     \n"
SCODE &= !"    // Three gradient vectors rolled into a matrix, constructed with offset greyscale texture values.     \n"
SCODE &= !"    mat3 m = mat3( tex3D(tx, p - e.xyy, n), tex3D(tx, p - e.yxy, n), tex3D(tx, p - e.yyx, n)); \n"
SCODE &= !"     \n"
SCODE &= !"    vec3 g = vec3(0.299, 0.587, 0.114)*m; // Converting to greyscale. \n"
SCODE &= !"    g = (g - dot(tex3D(tx,  p , n), vec3(0.299, 0.587, 0.114)) )/e.x; g -= n*dot(n, g); \n"
SCODE &= !"                       \n"
SCODE &= !"    return normalize( n + g*bf ); // Bumped normal. ""bf"" - bump factor. \n"
SCODE &= !"	 \n"
SCODE &= !"} \n"
SCODE &= !" \n"
SCODE &= !"// Standard hue rotation formula. \n"
SCODE &= !"vec3 rotHue(vec3 p, float a){ \n"
SCODE &= !" \n"
SCODE &= !"    float c = cos(a), s = sin(a); \n"
SCODE &= !" \n"
SCODE &= !"    mat3 hr = mat3(0.299,  0.587,  0.114,  0.299,  0.587,  0.114,  0.299,  0.587,  0.114) + \n"
SCODE &= !"        	  mat3(0.701, -0.587, -0.114, -0.299,  0.413, -0.114, -0.300, -0.588,  0.886) * c + \n"
SCODE &= !"        	  mat3(0.168,  0.330, -0.497, -0.328,  0.035,  0.292,  1.250, -1.050, -0.203) * s; \n"
SCODE &= !"							  \n"
SCODE &= !"    return clamp(p*hr, 0., 1.); \n"
SCODE &= !"} \n"
SCODE &= !" \n"
SCODE &= !"// Screen pattern. Simple, but effective. The idea to go with this was inspired by Dmitry Andreev's really \n"
SCODE &= !"// cool ""pixelScreen"" shader, here: https://www.shadertoy.com/view/XdG3Wc \n"
SCODE &= !"// \n"
SCODE &= !"// His pixel pattern is a little fancier, mainly because he's using way more code... The fact that he won  \n"
SCODE &= !"// Assembly a couple of times might also be a factor. :) \n"
SCODE &= !"float DotPattern(vec2 p){ \n"
SCODE &= !"     \n"
SCODE &= !"    // Partition space into multiple squares. \n"
SCODE &= !"    vec2 fp = abs(fract(p)-0.5)*2.; \n"
SCODE &= !"     \n"
SCODE &= !"    // Rounded circle, for the overlay, or vignette, if you prefer. \n"
SCODE &= !"    fp = pow(fp, vec2(8.)); \n"
SCODE &= !"    float r = max(1. - pow(fp.x + fp.y, 1.), 0.); \n"
SCODE &= !"     \n"
SCODE &= !"    // More squarish (Chebyshev) version of the above. \n"
SCODE &= !"    //fp = pow(fp, vec2(8.)); \n"
SCODE &= !"    //float r = 1. - max(fp.x, fp.y); \n"
SCODE &= !"     \n"
SCODE &= !"    // Single value for each square. Used for IDs and a bunch of other things, but in this  \n"
SCODE &= !"    // case it'll give the square a homogeneous color. \n"
SCODE &= !"    p = floor(p);  \n"
SCODE &= !"     \n"
SCODE &= !"    // The blocky pattern value. Made up, but you could use all kinds of things, like Voronoi, etc.  \n"
SCODE &= !"    float c = dot(sin(p/4. - cos(p.yx/.2 + iGlobalTime/4.)), vec2(.5)); \n"
SCODE &= !" \n"
SCODE &= !"    c = fract(c * 7.0); // Mixing it up, for no particular reason. \n"
SCODE &= !" \n"
SCODE &= !"    return c*r; // Pixel shade, multiplied by the rounded square vignette. Range: [0, 1]. \n"
SCODE &= !"     \n"
SCODE &= !"} \n"
SCODE &= !" \n"
SCODE &= !" \n"
SCODE &= !"void mainImage( out vec4 fragColor, in vec2 fragCoord ){ \n"
SCODE &= !"    \n"
SCODE &= !"     \n"
SCODE &= !"	// Screen coordinates. \n"
SCODE &= !"	vec2 u = (fragCoord - iResolution.xy*0.5)/iResolution.y; \n"
SCODE &= !"	 \n"
SCODE &= !"	// Camera Setup. \n"
SCODE &= !"    vec3 ro = camPath(iGlobalTime*1.5); // Camera position, doubling as the ray origin. \n"
SCODE &= !"    vec3 lk = camPath(iGlobalTime*1.5 + .1);  // ""Look At"" position. \n"
SCODE &= !"    vec3 lp = camPath(iGlobalTime*1.5 + 2.) + vec3(0, 2, 0); // Light position, somewhere near the moving camera. \n"
SCODE &= !" \n"
SCODE &= !" \n"
SCODE &= !"    // Using the above to produce the unit ray-direction vector. \n"
SCODE &= !"    float FOV = 1.57; // FOV - Field of view. \n"
SCODE &= !"    vec3 fwd = normalize(lk-ro); \n"
SCODE &= !"    vec3 rgt = normalize(vec3(fwd.z, 0., -fwd.x ));  \n"
SCODE &= !"    vec3 up = cross(fwd, rgt); \n"
SCODE &= !" \n"
SCODE &= !"    // Unit direction ray. \n"
SCODE &= !"    vec3 rd = normalize(fwd + FOV*(u.x*rgt + u.y*up)); \n"
SCODE &= !"  \n"
SCODE &= !"    vec2 a = sin(vec2(1.5707963, 0) - camPath(lk.z).x/12.);  \n"
SCODE &= !"    mat2 rM = mat2(a, -a.y, a.x); \n"
SCODE &= !"    rd.xy = rd.xy*rM; // Apparently, ""rd.xy *= rM"" doesn't work on some setups. Crazy. \n"
SCODE &= !" \n"
SCODE &= !"     \n"
SCODE &= !"    // Raymarching. \n"
SCODE &= !"    const float FAR = 50.0; \n"
SCODE &= !"    float t = 0.0, h; \n"
SCODE &= !"    for(int i = 0; i < 96; i++){ \n"
SCODE &= !"     \n"
SCODE &= !"        h = map(ro+rd*t); \n"
SCODE &= !"        // Note the ""t*b + a"" addition. Basically, we're putting less emphasis on accuracy, as \n"
SCODE &= !"        // ""t"" increases. It's a cheap trick that works in most situations... Not all, though. \n"
SCODE &= !"        if(abs(h)<0.001*(t*.75 + .25) || t>FAR) break;//*(t*.5 + 1.) \n"
SCODE &= !"        t += h*.75; \n"
SCODE &= !"        //t += step(.5, t)*h*.25 + h*.5; \n"
SCODE &= !"         \n"
SCODE &= !"    } \n"
SCODE &= !"     \n"
SCODE &= !"    vec3 col = vec3(0); \n"
SCODE &= !"     \n"
SCODE &= !"    // Hit object, so color the pixel.  \n"
SCODE &= !"    if(t<FAR){ \n"
SCODE &= !"         \n"
SCODE &= !"        // This looks a little messy and haphazard, but it's really just some basic lighting, and application \n"
SCODE &= !"        // of the following material properties: Metal = 1., Walls = 2., Screens = 3.. \n"
SCODE &= !"     \n"
SCODE &= !"        float ts = 2.; \n"
SCODE &= !"        // Global object ID. It needs to be saved just after the raymarching equation, since other ""map"" calls, \n"
SCODE &= !"        // like normal calculations will give incorrect results. Found that out the hard way. :) \n"
SCODE &= !"        float saveObjID = objID;  \n"
SCODE &= !"         \n"
SCODE &= !"         \n"
SCODE &= !"        vec3 pos = ro + rd*t; // Scene postion. \n"
SCODE &= !"        vec3 pOffs = pos - vec3(camPath(pos.z).xy, 0); // Postion, offset by the path.  \n"
SCODE &= !"        vec3 nor = calcNormal(pos); // Normal. \n"
SCODE &= !"         \n"
SCODE &= !"        // Apply some subtle texture bump mapping to the walls and the metal tubing, but not the screen. \n"
SCODE &= !"        // I should probably get rid of that ""if"" sigh later, but it seems OK for now. \n"
SCODE &= !"        if(saveObjID<2.5) nor = texBump(iChannel0, pOffs*ts, nor, 0.002 + step(saveObjID, 1.5)*0.012); \n"
SCODE &= !"         \n"
SCODE &= !"         \n"
SCODE &= !"		col = tex3D(iChannel0, pOffs*ts, nor); // Texture pixel at the scene postion. \n"
SCODE &= !"        col = smoothstep(-.3, .8, col)*vec3(1., .8, .7); // Process the color a little. \n"
SCODE &= !" \n"
SCODE &= !"        // More fake lighting. This was just a bit of trial-and-error to produce some repetitive, \n"
SCODE &= !"        // slightly overhead, spotlights in each of the modules. Cylinder in XY, sine repeat \n"
SCODE &= !"        // in the Z direction... Something like that. \n"
SCODE &= !"        float spot = max(2. - length(pOffs.xy - vec2(0, 1)), 0.)*(sin((pOffs.z)*3.14159 + 1.57)*.5+.5); \n"
SCODE &= !"        spot = smoothstep(0.25, 1., spot); \n"
SCODE &= !"         \n"
SCODE &= !"         \n"
SCODE &= !"         \n"
SCODE &= !"        float occ = calcAO( pos, nor ); // Occlusion. \n"
SCODE &= !"		vec3  li = normalize( lp - pos ); // Point light. \n"
SCODE &= !"        float dif = clamp(dot(nor, li), 0.0, 1.0); // Diffuse. \n"
SCODE &= !"        float spe = pow(max(dot(reflect(-li, nor), -rd), 0.), 8.); // Object specular. \n"
SCODE &= !"        float spe2 = 0.; // Global specular. \n"
SCODE &= !" \n"
SCODE &= !"             \n"
SCODE &= !" \n"
SCODE &= !"        vec3  rCol = vec3(0); // Reflection color. Mostly fake. \n"
SCODE &= !"         \n"
SCODE &= !"        // If the metal tubing or the screen is hit, apply the individual properties. \n"
SCODE &= !"        if(saveObjID>1.5){  \n"
SCODE &= !"			 \n"
SCODE &= !"            // Grey out the limestone wall color. \n"
SCODE &= !"            col = vec3(1)*dot(col*.7+.2, vec3(.299, .587, .114)); \n"
SCODE &= !"            // Add some fake reflection. Not reliable, but it's subtle. \n"
SCODE &= !"            rCol = tex3D(iChannel0, (pOffs + reflect(rd, nor))*ts, nor); \n"
SCODE &= !"            col += rCol*.25 + spot*.25; \n"
SCODE &= !"            spe2 = spe*spe*.25; // Ramp up the global specular a bit. \n"
SCODE &= !"             \n"
SCODE &= !"        }          \n"
SCODE &= !"         \n"
SCODE &= !"        // If just the screen has been hit, apply some extra properties, then draw the screen image. \n"
SCODE &= !"        // I could just write ""saveObjID == 3.."" but I get a little paranoid where floats are concerned. :) \n"
SCODE &= !"        if(saveObjID>2.5){ \n"
SCODE &= !" \n"
SCODE &= !"            // For the screen image, we're interested in the offset height and depth positions. Ie: pOffs.zy. \n"
SCODE &= !"             \n"
SCODE &= !"            // Pixelized dot pattern shade. \n"
SCODE &= !"            float c = DotPattern(pOffs.zy*36.+.5); \n"
SCODE &= !"             \n"
SCODE &= !"            // Applying some color to the shade. \n"
SCODE &= !"            col = vec3(min(c*1.5, 1.), pow(c, 2.5), pow(c, 12.)); \n"
SCODE &= !"            // Mixing the colors around a little. Made up. \n"
SCODE &= !"            col = mix(col.zyx, col, sin(dot(pos, vec3(.333))*3.14159*6.)*.34+.66); \n"
SCODE &= !"			 \n"
SCODE &= !"            // Individual screen ID or sorts. \n"
SCODE &= !"            float id = hash(dot(floor(pOffs + vec3(.0, .5, .5)), vec3(7, 157, 113))); \n"
SCODE &= !"             \n"
SCODE &= !"            // Use the screen ID to give it a different random hue. \n"
SCODE &= !"            col = rotHue(col, floor(id*12.)/12.*6.283/2.);  \n"
SCODE &= !"             \n"
SCODE &= !"            col += rCol*rCol*.5; // Screen reflection.             \n"
SCODE &= !"             \n"
SCODE &= !"            dif += .5; // Make the screen appear self illuminating, but increasing the diffuse. \n"
SCODE &= !"            spe += .25; \n"
SCODE &= !"             \n"
SCODE &= !"        } \n"
SCODE &= !"        \n"
SCODE &= !"        // Combining everything together to produce the scene color. \n"
SCODE &= !"        col *= (dif + .25 + spot*.5 + vec3(.25, .3, .5)*spe) + spe2; \n"
SCODE &= !"        col *= occ; // Applying occlusion. \n"
SCODE &= !"        \n"
SCODE &= !"         \n"
SCODE &= !"    } \n"
SCODE &= !"     \n"
SCODE &= !"    // Applying some very slight fog in the distance. This is technically an inside scene... \n"
SCODE &= !"    // Or is it underground... Who cares, it's just a shader. :) \n"
SCODE &= !"    col = mix(min(col, 1.), vec3(0), 1.-exp(-t*t/FAR/FAR*15.));//smoothstep(0., FAR-20., t) \n"
SCODE &= !"     \n"
SCODE &= !"    // Done. \n"
SCODE &= !"    fragColor = vec4(col, 1.0); \n"
SCODE &= !"     \n"
SCODE &= !"} \n"


#include once "fbgfx.bi"
#include once "GL/gl.bi"
#include once "GL/glext.bi"

#ifndef NULL
#define NULL 0
#endif


type vec3
  as GLfloat x,y,z
end type

sub ErrorExit(msg as string)
  if screenptr() then screen 0
  dim as integer w,h
  screeninfo w,h : w*=0.75:h*=0.75
  screenres w,h
  print msg
  print "press any key to quit ..."
  beep : sleep : end 1
end sub

' define OpenGL proc's
#define glDefine(n) dim shared as PFN##n##PROC n
' texture
'glDefine(glActiveTexture)
' shader
glDefine(glCreateShader)
glDefine(glDeleteShader)
glDefine(glShaderSource)
glDefine(glCompileShader)
glDefine(glGetShaderiv)
glDefine(glGetShaderInfoLog)
' program
glDefine(glCreateProgram)
glDefine(glDeleteProgram)
glDefine(glAttachShader)
glDefine(glDetachShader)
glDefine(glLinkProgram)
glDefine(glGetProgramiv)
glDefine(glGetProgramInfoLog)
glDefine(glUseProgram)
' uniform
glDefine(glGetUniformLocation)
glDefine(glUniform1f)
glDefine(glUniform2f)
glDefine(glUniform3f)
glDefine(glUniform4f)
glDefine(glUniform1i)
#undef glDefine

sub glScreen(w as integer=640, h as integer=360, b as integer=32, d as integer=24, s as integer=0, f as integer=0)
  if ScreenPtr() then screen 0
  ScreenControl FB.SET_GL_STENCIL_BITS,s
  ScreenControl FB.SET_GL_DEPTH_BITS  ,d
  if ScreenRes(w,h,b,,FB.GFX_OPENGL or iif(f<>0,FB.GFX_FULLSCREEN,0)) then
    ErrorExit("screenres(" & w & "," & h &") failed !")
  end if
  Windowtitle "offline shadertoy.com"

  flip
  ' get OpenGL proc's (abort if something goes wrong)
  #define glProc(n) n = ScreenGLProc(#n) : if n = 0 then ErrorExit(#n)
  ' texture
  'glProc(glActiveTexture)
  ' shader
  glProc(glCreateShader)
  glProc(glDeleteShader)
  glProc(glShaderSource)
  glProc(glCompileShader)
  glProc(glGetShaderiv)
  glProc(glGetShaderInfoLog)
  ' program
  glProc(glCreateProgram)
  glProc(glDeleteProgram)
  glProc(glAttachShader)
  glProc(glDetachShader)
  glProc(glLinkProgram)
  glProc(glGetProgramiv)
  glProc(glGetProgramInfoLog)
  glProc(glUseProgram)
  ' uniform
  glProc(glGetUniformLocation)
  glProc(glUniform1f)
  glProc(glUniform2f)
  glProc(glUniform3f)
  glProc(glUniform4f)
  glProc(glUniform1i)
  #undef glProc
end sub

type ShaderToy
  declare destructor
  declare function CompileFile(Filename as string) as boolean
  declare function CompileCode(Code as string) as boolean
  as GLuint FragmentShader
  as GLuint ProgramObject
  as string Shaderlog
end type
destructor ShaderToy
  if ProgramObject then 
   glUseprogram(0)
   if FragmentShader  then 
     glDetachShader(ProgramObject,FragmentShader)
     glDeleteShader(FragmentShader)
   end if
   glDeleteProgram(ProgramObject)
  end if
end destructor

function ShaderToy.CompileFile(filename as string) as boolean
  dim as string code
  var hFile = FreeFile()
  if open(filename,for input, as #hFile) then 
    ShaderLog = "can't read shader: " & chr(34) & filename  & chr(34) & " !"
    return false
  end if
  while not eof(hFile)
    dim as string aLine
    line input #hFile,aLine
    code &= aLine & !"\n"
  wend
  close #hFile
  return CompileCode(code)
end function

function ShaderToy.CompileCode(UserCode as string) as boolean
  dim as GLint logSize
  dim as GLint status
  dim as string FragmentProlog
  FragmentProlog & =!"uniform float     iGlobalTime;  // shader playback time (in seconds)\n"
  FragmentProlog & =!"uniform vec3      iResolution;  // viewport resolution (in pixels)\n"
  FragmentProlog & =!"uniform vec4      iMouse;       // mouse pixel coords. xy: current (if MLB down), zw: click\n"
  FragmentProlog & =!"uniform vec4      iDate;        // (year, month, day, time in seconds)\n"
  FragmentProlog & =!"uniform sampler2D iChannel0;\n"
  FragmentProlog & =!"uniform sampler2D iChannel1;\n"
  FragmentProlog & =!"uniform sampler2D iChannel2;\n"
  FragmentProlog & =!"uniform sampler2D iChannel3;\n"
  dim as string FragmentEpilog
  FragmentEpilog &= !"void main() {\n"
  FragmentEpilog &= !"  vec4 color;\n"
  FragmentEpilog &= !"  // call user shader\n"
  FragmentEpilog &= !"  mainImage(color, gl_FragCoord.xy);\n"
  FragmentEpilog &= !"  color.w = 1.0;\n"
  FragmentEpilog &= !"  gl_FragColor = color;\n"
  FragmentEpilog &= !"}\n"

  dim as string FragmentCode = FragmentProlog & UserCode & FragmentEpilog

  FragmentShader = glCreateShader(GL_FRAGMENT_SHADER)
  if FragmentShader=0 then 
    ShaderLog = "glCreateShader(GL_FRAGMENT_SHADER) failed !"
    return false
  end if
  dim as GLchar ptr pCode=strptr(FragmentCode)
  glShaderSource (FragmentShader, 1, @pCode, NULL)
  glCompileShader(FragmentShader)
  glGetShaderiv  (FragmentShader, GL_COMPILE_STATUS, @status)
  if status = GL_FALSE then 
    glGetShaderiv(FragmentShader, GL_INFO_LOG_LENGTH, @logSize)
    ShaderLog = space(logSize)
    glGetShaderInfoLog(FragmentShader, logSize, NULL, cptr(GLchar ptr,strptr(ShaderLog)) )
    ShaderLog = !"glCompileShader(FragmentShader) failed !\n" & Shaderlog
    glDeleteShader(FragmentShader) : FragmentShader = 0
    return false
  end if

  ProgramObject = glCreateProgram()
  if ProgramObject=0 then 
    ShaderLog = "glCreateProgram() failed !"
    glDeleteShader(FragmentShader) : FragmentShader = 0
    return false
  end if
  glAttachShader(ProgramObject,FragmentShader)
  glLinkProgram (ProgramObject)
  glGetProgramiv(ProgramObject, GL_LINK_STATUS, @status)
  if (status = GL_FALSE) then
    glGetProgramiv(ProgramObject, GL_INFO_LOG_LENGTH, @logSize)
    ShaderLog = space(logSize)
    glGetProgramInfoLog (ProgramObject, logSize, NULL, cptr(GLchar ptr,strptr(ShaderLog)) )
    ShaderLog = !"glLinkProgram() failed !\n" & Shaderlog
    glDeleteShader(FragmentShader) : FragmentShader = 0
    return false
  end if
  return true
end function

'
' main
'


' init Screenres, create the OpenGL context and load some OpenGL procs.
dim as integer pixels=640
' wide screen 16:9
glScreen pixels,pixels/16*9


' get curent resolution
dim as integer scr_w,scr_h
screeninfo scr_w,scr_h

dim as vec3 v3
v3.x=scr_w     ' width in pixle
v3.y=scr_h     '`height in pixle
v3.z=v3.x/v3.y ' pixel ratio

dim as ShaderToy Shader

if Shader.CompileCode(SCODE)=false then
  ErrorExit Shader.ShaderLog
end if  

' enable shader
glUseProgram(Shader.ProgramObject)

' get uniforms locations in shader program
var iGlobalTime = glGetUniformLocation(Shader.ProgramObject,"iGlobalTime")
var iResolution = glGetUniformLocation(Shader.ProgramObject,"iResolution")
var iMouse      = glGetUniformLocation(Shader.ProgramObject,"iMouse")

' set vec3 iResolution
glUniform3f(iResolution,v3.x,v3.y,v3.z)

dim as integer mx,my,mb,frames,fps
dim as double tStart = Timer()
dim as double tLast=tStart
while inkey=""
  dim as double tNow=Timer()
  ' set uniform float iGlobalTime
  glUniform1f(iGlobalTime,tNow-tStart)
/'
  if frames mod 3=0 then
    ' set vec4 iMouse
    if getMouse(mx,my,,mb)=0 then
      if mb then
        glUniform4f(iResolution,mx,scr_h-my,1,1)
      else
        glUniform4f(iResolution,0,0,0,0)
      end if
    end if
  end if
'/

  'glClear(GL_COLOR_BUFFER_BIT)

  ' draw a rectangle (2 triangles over the whole screen)
  glRectf(-1,-1,1,1)
  flip ' swap the buffers

  frames+=1
  ' update fps
  if frames mod 24=0 then
    fps=24/(tNow-tLast)
    windowtitle "fps: " & fps
    tLast=tNow
  end if

wend

' disable shader
glUseProgram(0)
leopardpm
Posts: 1795
Joined: Feb 28, 2009 20:58

Re: Can you post your FPS result please ?

Post by leopardpm »

nice! I get 15fps with that one... really nice work for just being 'bored'!
Post Reply