Skip to content

Instantly share code, notes, and snippets.

@dom96

dom96/N.nim Secret

Created December 4, 2013 22:23
Show Gist options
  • Save dom96/485c7a97472d31dc6b6e to your computer and use it in GitHub Desktop.
Save dom96/485c7a97472d31dc6b6e to your computer and use it in GitHub Desktop.
import opengl, glfw3/glfw3, math, unsigned, strutils
type
TPt = object
x, y, z, vx, vy, vz, r, life: float64
bis: bool
TVertex = object
pos: array[3, GLfloat]
normal: array[3, GLfloat]
const
PrintFrames = true
Title = "ParticleBench"
Width = 800
Height = 600
MinX = -80
MaxX = 80
MinY = -90
MaxY = 50
MinDepth = 50
MaxDepth = 250
StartRange = 15
StartX = (MinX + (MinX+MaxX)/2)
StartY = MaxY
StartDepth = (MinDepth + (MinDepth+MaxDepth)/2)
PointsPerSec = 2000
MaxInitVel = 7
MaxLife = 5000
MaxScale = 4
WindChange = 2000
MaxWind = 3
SpawnInterval = 0.01
RunningTime = ((MaxLife div 1000) * 5)
MaxPts = RunningTime * PointsPerSec
NumVertices = 24
NumNormals = NumVertices / 4
var
initT = 0.0
endT = 0.0
frameDur = 0.0
spwnTmr = 0.0
cleanupTmr = 0.0
runTmr = 0.0
frames: array[RunningTime * 1000, float64]
curFrame = 0
pts: array[MaxPts, TPt]
vertices: array[NumVertices, TVertex]
numPts = 0
minPt = 0
seed = 1234569'u32
curVertex = 0
curNormal = 0
gVBO: GLuint = 0
windX = 0.0'f64
windY = 0.0'f64
windZ = 0.0'f64
gravity = 0.0'f64
ambient = [Glfloat(0.8), 0.05, 0.1, 1.0]
diffuse = [Glfloat(1.0), 1.0, 1.0, 1.0]
lightPos = [GlFloat(MinX + (MaxX-MinX)/2), MaxY, MinDepth, 0]
proc newVertex(x, y, z: GLfloat) =
var thisVertex: TVertex
thisVertex.pos[0] = x
thisVertex.pos[1] = y
thisVertex.pos[2] = z
vertices[curVertex] = thisVertex
curVertex.inc
proc newNormal(nx, ny, nz: GLfloat) =
for i in curNormal * 4 .. <((curNormal + 1) * 4):
vertices[i].normal[0] = nx
vertices[i].normal[1] = ny
vertices[i].normal[2] = nz
curNormal.inc
proc xorRand: uint32 =
seed = seed xor (seed shl 13)
seed = seed xor (seed shr 17)
seed = seed xor (seed shl 5)
return seed
proc movePts(secs: float64) =
for i in minPt .. numPts:
if not pts[i].bis:
continue
pts[i].x += pts[i].vx * secs
pts[i].y += pts[i].vy * secs
pts[i].z += pts[i].vz * secs
pts[i].vx += windX * 1 / pts[i].r
pts[i].vy += windY * 1 / pts[i].r
pts[i].vy -= gravity
pts[i].vz += windZ * 1 / pts[i].r
pts[i].life -= secs
if pts[i].life <= 0:
pts[i].bis = false
proc spawnPts(secs: float64) =
let num = secs * PointsPerSec
for i in 0 .. <num.int:
var pt = TPt(
x: 0 + float64(xorRand() mod START_RANGE) - START_RANGE/2,
y: startY,
z: startDepth + float64(xorRand() mod START_RANGE) - START_RANGE/2,
vx: float64(xorRand() mod MaxInitVel),
vy: float64(xorRand() mod MaxInitVel),
vz: float64(xorRand() mod MaxInitVel),
r: float64(xorRand() mod (MAX_SCALE*100)) / 200,
life: float64(xorRand() mod MaxLife) / 1000,
bis: true
)
pts[numPts] = pt
numPts.inc
proc doWind() =
windX += ( float64(xorRand() mod WIND_CHANGE)/WIND_CHANGE - WIND_CHANGE/2000) * frameDur
windY += ( float64(xorRand() mod WIND_CHANGE)/WIND_CHANGE - WIND_CHANGE/2000) * frameDur
windZ += ( float64(xorRand() mod WIND_CHANGE)/WIND_CHANGE - WIND_CHANGE/2000) * frameDur
if abs(windX) > MAX_WIND:
windX = windX * -0.5
if abs(windY) > MAX_WIND:
windY *= -0.5
if abs(windZ) > MAX_WIND:
windZ *= -0.5
proc checkColls() =
for i in minPt .. numPts:
if not pts[i].bis:
continue
if Pts[i].X < MIN_X:
Pts[i].X = MIN_X + Pts[i].R
Pts[i].VX *= -1.1 # These particles are magic; they accelerate by 10% at every bounce off the bounding box
if Pts[i].X > MAX_X:
Pts[i].X = MAX_X - Pts[i].R
Pts[i].VX *= -1.1
if Pts[i].Y < MIN_Y:
Pts[i].Y = MIN_Y + Pts[i].R
Pts[i].VY *= -1.1
if Pts[i].Y > MAX_Y:
Pts[i].Y = MAX_Y - Pts[i].R
Pts[i].VY *= -1.1
if Pts[i].Z < MIN_DEPTH:
Pts[i].Z = MIN_DEPTH + Pts[i].R
Pts[i].VZ *= -1.1
if Pts[i].Z > MAX_DEPTH:
Pts[i].Z = MAX_DEPTH - Pts[i].R
Pts[i].VZ *= -1.1
proc cleanupPtPool =
for i in minPt .. numPts:
if Pts[i].bis:
minPt = i
break
proc initScene =
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glClearColor(0.1, 0.1, 0.6, 1.0)
glClearDepth(1)
glDepthFunc(GL_LEQUAL)
glLightfv(GL_LIGHT0, GL_AMBIENT, addr ambient[0])
glLightfv(GL_LIGHT0, GL_DIFFUSE, addr diffuse[0])
glLightfv(GL_LIGHT0, GL_POSITION, addr lightPos[0])
glEnable(GL_LIGHT0)
glViewport(0, 0, WIDTH, HEIGHT)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glFrustum(-1, 1, -1, 1, 1.0, 1000.0)
glRotatef(20, 1, 0, 0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glPushMatrix()
template offsetof(typ, field): expr = (var dummy: typ; cast[int](addr(dummy.field)) - cast[int](addr(dummy)))
proc loadCubeToGPU: bool =
newVertex(-1, -1, 1)
newVertex(1, -1, 1)
newVertex(1, 1, 1)
newVertex(-1, 1, 1)
newNormal(0, 0, 1)
newVertex(-1, -1, -1)
newVertex(-1, 1, -1)
newVertex(1, 1, -1)
newVertex(1, -1, -1)
newNormal(0, 0, -1)
newVertex(-1, 1, -1)
newVertex(-1, 1, 1)
newVertex(1, 1, 1)
newVertex(1, 1, -1)
newNormal(0, 1, 0)
newVertex(-1, -1, -1)
newVertex(1, -1, -1)
newVertex(1, -1, 1)
newVertex(-1, -1, 1)
newNormal(0, -1, 0)
newVertex(1, -1, -1)
newVertex(1, 1, -1)
newVertex(1, 1, 1)
newVertex(1, -1, 1)
newNormal(1, 0, 0)
newVertex(-1, -1, -1)
newVertex(-1, -1, 1)
newVertex(-1, 1, 1)
newVertex(-1, 1, -1)
newNormal(-1, 0, 0)
glGenBuffers(1, addr gVBO)
glBindBuffer(GL_ARRAY_BUFFER, gVBO)
glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(NUM_VERTICES * sizeof(TVertex)), addr vertices[0], GL_STATIC_DRAW)
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_NORMAL_ARRAY)
glVertexPointer(3, cGL_FLOAT, sizeof(TVertex).glsizei, nil)
glNormalPointer(cGL_FLOAT, sizeof(TVertex).glsizei, cast[pglvoid](offsetof(TVertex, normal)))
return true
proc cleanupBuffers =
glDeleteBuffers( 1, addr gVBO)
glDisableClientState( GL_NORMAL_ARRAY )
glDisableClientState( GL_VERTEX_ARRAY )
proc renderPts =
for i in minPt .. numPts:
if (Pts[i].bis == false):
continue
var pt: ptr TPt = addr pts[i]
glMatrixMode(GL_MODELVIEW)
glPopMatrix()
glPushMatrix()
glTranslatef(pt.X, pt.Y, -(pt.Z))
glScalef(pt.R * 2, pt.R * 2, pt.R * 2)
glColor4f(0.7, 0.9, 0.2, 1)
glDrawArrays(GL_QUADS, 0, NUM_VERTICES)
when isMainModule:
init()
glfwWindowHint(GLFW_SAMPLES, 2)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2)
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1)
var window = newWin((Width.positive, Height.positive), Title)
window.setCurrentContext()
glfwSwapInterval(0)
loadExtensions()
initScene()
let version = window.glVersion()
if version.ver < glv21:
quit("OpenGL 2 not supported.")
discard loadCubeToGPU()
while not shouldClose(window):
initT = glfwGetTime()
movePts(frameDur)
doWind()
if (spwnTmr >= SPAWN_INTERVAL):
spawnPts(SPAWN_INTERVAL)
spwnTmr -= SPAWN_INTERVAL
if (cleanupTmr >= MAX_LIFE/1000):
cleanupPtPool()
cleanupTmr = 0
checkColls()
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
renderPts()
window.swapBufs()
pollEvents()
endT = glfwGetTime()
frameDur = endT-initT
spwnTmr += frameDur
cleanupTmr += frameDur
runTmr += frameDur
if (runTmr > MAX_LIFE/1000):
frames[curFrame] = frameDur
curFrame += 1
if (runTmr >= RUNNING_TIME):
var sum = 0'f64
for i in 0 .. <curFrame:
sum += frames[i]
var mean = sum / curFrame.float64
echo("Average framerate was: $1 frames per second." % formatFloat(1/mean))
var sumDiffs = 0.0
for i in 0 .. <curFrame:
sumDiffs += pow((1/frames[i])-(1/mean), 2)
var variance = sumDiffs / curFrame.float64
var sd = sqrt(variance)
echo("The standard deviation was: $1 frames per second." % sd.formatFloat)
if PRINT_FRAMES:
stdout.write("--:")
for i in 0 .. <curFrame:
stdout.write(formatFloat(1/frames[i]))
stdout.write(",")
stdout.write(".--")
break
cleanupBuffers()
window.destroy()
glfwTerminate()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment