Post by Bentschi » 02 Sep 2014, 11:52
Hab das nachfolgende Projekt mal auf Eis gelegt...
Möglicherweise kannst du ja was davon verwenden.
In TODO hab ich vermerkt was mir noch fehlt.
Was mir noch auf die Schnelle einfällt ist, dass ich die Kameraklasse nicht richtig getestet habe.
Und ein problem mit Licht und Materialien -> die ich in nem Shader berechnen wollte für multiple Lichter (mehr als die 8 die meine Graka berechnen würde).
Alternativ könnte man auch den Lichtshader weg lassen und das Hauptlicht (zB. Sonne) und die dem Model nächsten 7 Lichter verwenden (Jede Graka mit OpenGL unterstützt min. 8 bis max. 32).
Ansonsten sollte alles relativ performant sein, da alle Objekte Displaylisten verwenden.
Geht zwar etwas auf den Grafikspeicher, aber Texturen sind ohnehin schlimmer für den Speicher
.
Die Idee ist, wenn sich kein Model, Textur, Kamera, ... in der Szene ändert reicht ein einziger Aufruf einer Displayliste die die komplette Szene zeichnet.
Dann noch wglMakeCurrent, SwapBuffers und glClear... sind nur 4 DllCalls.
Btw. diese Engine war auch dafür gedacht, dass mehrere Monitore in Vollbild bzw. mehrere Fenster verwendet werden können.
Daher die umständliche Initialisierung der Renderer-Klasse, die untereinander die Renderkontexte (Texturen, Displaylisten, etc.) teilen.
Code: Select all
; TODO:
;============================
; - Multiple lights
; - Shaders (delete, uniform)
; - Model loading
; - Bumpmaps
; - Fog
; - Blending
#NoEnv
SetWorkingDir, % A_ScriptDir
SetBatchLines, -1
; Init GUI
Gui, +LastFound
Gui, show, w640 h480, AHK 3D Engine
; Init 3D stuff
renderer := new 3D.Renderer(WinExist())
if (!IsObject(renderer))
MsgBox, % "ERROR: Can't create renderer (" renderer ")"
viewport := new 3D.Viewport(renderer)
camera := new 3D.Camera()
camera.perspective(90, viewport, 0.1, 100)
; Load a texture
tex := new 3D.Texture()
tex.load("test.jpg")
; Create a material
mat := new 3D.Material()
mat.texture(tex)
; Create a cube model
model := new 3D.Model()
a := 0.5
b := -0.5
;pos: x,y,z
;tex: | | | x,y
;normal: | | | | | x,y,z
; | | | | | | | |
cube := [a,a,a, 0,0, 0,0,1, b,a,a, 1,0, 0,0,1, b,b,a, 1,1, 0,0,1, a,b,a, 0,1, 0,0,1 ;front
, a,a,a, 0,0, 1,0,0, a,b,a, 1,0, 1,0,0, a,b,b, 1,1, 1,0,0, a,a,b, 0,1, 1,0,0 ;right
, a,a,a, 0,0, 0,1,0, b,a,a, 1,0, 0,1,0, b,a,b, 1,1, 0,1,0, a,a,b, 0,1, 0,1,0 ;top
, a,a,b, 0,0, 0,0,-1, b,a,b, 1,0, 0,0,-1, b,b,b, 1,1, 0,0,-1, a,b,b, 0,1, 0,0,-1 ;back
, b,a,a, 0,0, -1,0,0, b,b,a, 1,0, -1,0,0, b,b,b, 1,1, -1,0,0, b,a,b, 0,1, -1,0,0 ;left
, a,b,a, 0,0, 0,-1,0, b,b,a, 1,0, 0,-1,0, b,b,b, 1,1, 0,-1,0, a,b,b, 0,1, 0,-1,0] ;bottom
model.setQuads("3V2T3N", cube, mat)
model.translate(0, 0, -1.2)
light := new 3D.Light()
light.ambient(0.5, 0.5, 0.5, 1.0)
light.diffuse(1.0, 1.0, 1.0, 1.0)
light.specular(0.2, 0.2, 0.2, 1.0)
light.position(0.0, 0.5, 0.0, 1.0)
shader := new 3D.Shader()
shader.vertex("
(Join`n
void main(void)
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
}
)")
shader.fragment("
(Join`n
uniform sampler2D Texture0;
void main(void)
{
gl_FragColor = texture2D(Texture0, vec2(gl_TexCoord[0]));
}
)")
scene := new 3D.Scene()
scene.addChild(light)
scene.addChild(model)
scene.addChild(shader)
stopped := 0
SetTimer, timer, 30
return
timer:
if (!stopped && (GetKeyState("up") || GetKeyState("down") || GetKeyState("left") || GetKeyState("right")))
stopped := 1
if (!stopped)
model.rotate(1, 0.94, 1.71, 0.26)
if (stopped && GetKeyState("up"))
model.rotate(1, 1, 0, 0)
if (stopped && GetKeyState("down"))
model.rotate(-1, 1, 0, 0)
if (stopped && GetKeyState("left"))
model.rotate(1, 0, 1, 0)
if (stopped && GetKeyState("right"))
model.rotate(-1, 0, 1, 0)
renderer.render(scene, viewport, camera)
return
class 3D
{
static hOpenGL := DllCall("LoadLibrary", "str", "opengl32", "ptr")
static hGdiPlus := DllCall("LoadLibrary", "str", "gdiplus", "ptr")
class Renderer
{
static shareRenderer := 0
__new(wnd)
{
this.objType := "3D.Renderer"
if (!isObject(3D.Renderer.shareRenderer) && wnd!="_share")
3D.Renderer.shareRenderer := new 3D.Renderer("_share")
if (wnd=="_share")
{
lf := WinExist()
Gui, _3D_Renderer_ShareRenderer: +LastFound
Gui, _3D_Renderer_ShareRenderer:show, hide
wnd := WinExist()
WinExist("ahk_id " lf)
}
else if (!isObject(3D.Renderer.shareRenderer))
return 3D.Renderer.shareRenderer
this.hWnd := (isObject(wnd) && wnd.hasKey("hWnd")) ? wnd.hWnd : wnd
if (!(this.hDC := DllCall("GetDC", "ptr", this.hWnd, "ptr")))
return -3 ; ERROR: Can't get the device context
VarSetCapacity(pfd, 40, 0)
NumPut(40, pfd, 0, "ushort")
NumPut(1, pfd, 2, "ushort")
NumPut(0x25, pfd, 4, "uint")
NumPut(32, pfd, 9, "uchar")
NumPut(16, pfd, 23, "uchar")
if (!(pf := DllCall("ChoosePixelFormat", "ptr", this.hDC, "ptr", &pfd, "int")))
return -4 ; ERROR: Can't choose the pixel format
if (!DllCall("SetPixelFormat", "ptr", this.hDC, "int", pf, "ptr", &pfd))
return -5 ; ERROR: Can't select the pixel format
if (!(this.hRC := DllCall("opengl32\wglCreateContext", "ptr", this.hDC, "ptr")))
return -6 ; ERROR: Can't create the render context
if (!DllCall("opengl32\wglMakeCurrent", "ptr", this.hDC, "ptr", this.hRC))
return -7 ; ERROR: Can't activate the render context
if (IsObject(3D.Renderer.shareRenderer) && !DllCall("opengl32\wglShareLists", "ptr", this.hRC, "ptr", 3D.Renderer.shareRenderer.hRC))
return -8 ; ERROR: Can't share lists between render context's
DllCall("opengl32\glShadeModel", "uint", 0x1D01)
DllCall("opengl32\glHint", "uint", 0x0C50, "uint", 0x1102)
DllCall("opengl32\glEnable", "uint", 0x0DE1) ;texture
DllCall("opengl32\glEnable", "uint", 0x4000) ;light
DllCall("opengl32\glDepthFunc", "uint", 0x0203)
DllCall("SwapBuffers", "ptr", this.hDC)
}
__delete()
{
if (this.hRC)
{
DllCall("opengl32\wglMakeCurrent", "ptr", 0, "ptr", 0)
DllCall("opengl32\wglDeleteContext", "ptr", this.hRC)
}
if (this.hDC)
DllCall("ReleaseDC", "ptr", this.hWnd, "ptr", this.hDC)
}
render(scene, viewport, camera)
{
DllCall("opengl32\wglMakeCurrent", "ptr", this.hDC, "ptr", this.hRC)
DllCall("opengl32\glViewport", "int", viewport.x, "int", viewport.y, "int", viewport.width, "int", viewport.height)
DllCall("opengl32\glClear", "uint", 0x00004100)
DllCall("opengl32\glCallList", "uint", camera.list)
DllCall("opengl32\glCallList", "uint", scene.list)
DllCall("SwapBuffers", "ptr", this.hDC)
}
}
class Viewport
{
__new(renderer=0)
{
this.objType := "3D.Viewport"
this.x := this.y := 0
this.width := this.height := 512
if (renderer.objType="3D.Renderer")
this.renderer(renderer)
}
renderer(renderer)
{
VarSetCapacity(rc, 16, 0)
DllCall("GetClientRect", "ptr", renderer.hWnd, "ptr", &rc)
this.width := NumGet(rc, 8, "int")
this.height := NumGet(rc, 12, "int")
}
setViewport(x=0, y=0, width=512, height=512)
{
this.x := x
this.y := y
this.width := width
this.height := height
}
}
class Scene
{
__new()
{
this.list := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.shaderList := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.childs := []
this.shaders := []
}
__delete()
{
if (this.list)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
if (this.shaderList)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
}
_update()
{
glUseProgram := 3D._glProc("glUseProgramObjectARB", "glUseProgram")
if (glUseProgram)
{
DllCall("opengl32\glNewList", "uint", this.shaderList, "uint", 0x1300)
for sk,sv in this.shaders
DllCall(glUseProgram, "uint", sv.program)
DllCall("opengl32\glEndList")
}
DllCall("opengl32\glNewList", "uint", this.list, "uint", 0x1300)
for k,v in this.childs
{
DllCall("opengl32\glCallList", "uint", this.shaderList)
DllCall("opengl32\glCallList", "uint", v.list)
if (glUseProgram)
DllCall(glUseProgram, "uint", 0)
}
DllCall("opengl32\glEndList")
}
addChild(obj)
{
if (obj.objType="3D.Model" || obj.objType="3D.Light")
{
this.childs[Object(obj)] := obj
this._update()
}
if (obj.objType="3D.Shader")
{
this.shaders[Object(obj)] := obj
this._update()
}
}
}
class Transform
{
__new()
{
this.objType := "3D.Transform"
this.ptr := DllCall("HeapAlloc", "ptr", DllCall("GetProcessHeap", "ptr"), "uint", 0x8, "ptr", 64, "ptr")
this.list := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.identity()
this._update()
}
_update()
{
DllCall("opengl32\glNewList", "uint", this.list, "uint", 0x1300)
DllCall("opengl32\glMultMatrixf", "ptr", this.ptr)
DllCall("opengl32\glEndList")
}
__delete()
{
if (this.ptr)
DllCall("HeapFree", "ptr", DllCall("GetProcessHeap", "ptr"), "uint", 0, "ptr", this.ptr)
if (this.list)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
}
_glTransform(p*)
{
DllCall("opengl32\glMatrixMode", "uint", 0x1700)
DllCall("opengl32\glLoadMatrixf", "ptr", this.ptr)
DllCall(p*)
DllCall("opengl32\glGetFloatv", "uint", 0x0BA6, "ptr", this.ptr)
this._update()
}
identity()
{
return this._glTransform("opengl32\glLoadIdentity")
}
translate(x, y, z)
{
return this._glTransform("opengl32\glTranslatef", "float", x, "float", y, "float", z)
}
rotate(angle, x, y, z)
{
return this._glTransform("opengl32\glRotatef", "float", angle, "float", x, "float", y, "float", z)
}
scale(x, y, z)
{
return this._glTransform("opengl32\glScalef", "float", x, "float", y, "float", z)
}
}
class Camera
{
__new()
{
this.objType := "3D.Camera"
this.transform := new 3D.Transform()
this.list := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.depthTest := "_?"
}
__delete()
{
if (this.list)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
}
identity()
{
return this.transform.identity()
}
translate(x, y, z)
{
return this.transform.translate(-x, -y, -z)
}
rotate(angle, x, y, z)
{
return this.transform.rotate(angle, -x, -y, -z)
}
scale(x, y, z)
{
return this.transform.scale(-x, -y, -z)
}
_glCamera(p*)
{
DllCall("opengl32\glNewList", "uint", this.list, "uint", 0x1300)
DllCall("opengl32\glMatrixMode", "uint", 0x1701)
DllCall("opengl32\glLoadIdentity")
DllCall(p*)
DllCall("opengl32\glMatrixMode", "uint", 0x1700)
DllCall("opengl32\glLoadIdentity")
DllCall("opengl32\glCallList", "uint", this.transform.list)
DllCall((this.depthTest) ? "opengl32\glEnable" : "opengl32\glDisable", "uint", 0x0B71)
DllCall("opengl32\glEndList")
}
ortho(left, right, bottom, top, near, far)
{
if (this.depthTest=="_?")
this.depthTest := 0
this._glCamera("opengl32\glOrtho", "double", left, "double", right, "double", bottom, "double", top, "double", near, "double", far)
}
frustum(left, right, bottom, top, near, far)
{
if (this.depthTest=="_?")
this.depthTest := 1
this._glCamera("opengl32\glFrustum", "double", left, "double", right, "double", bottom, "double", top, "double", near, "double", far)
}
perspective(fov, aspect, near, far)
{
static pi := 3.1415926535897
aspect := (aspect.hasKey("objType") && aspect.objType="3D.Viewport") ? aspect.width/aspect.height : aspect
h := tan(fov/360*pi)*near
w := h*aspect
this.frustum(-w, w, -h, h, near, far)
}
}
class Model
{
__new()
{
this.objType := "3D.Model"
this.transform := new 3D.Transform()
this.list := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.data := []
}
__delete()
{
if (this.list)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
}
_update()
{
static f := {1:0, 2:1, 3:4, 4:7}
DllCall("opengl32\glNewList", "uint", this.list, "uint", 0x1300)
DllCall("opengl32\glPushMatrix")
DllCall("opengl32\glCallList", "uint", this.transform.list)
for i, d in this.data
{
if (d[4].objType!="3D.Material")
DllCall("opengl32\glDisable", "uint", 0x0B50)
if (d[4].objType="3D.Material")
{
DllCall("opengl32\glEnable", "uint", 0x0B50)
DllCall("opengl32\glCallList", "uint", d[4])
}
else
DllCall("opengl32\glBindTexture", "uint", 0x0DE1, "uint", 0)
DllCall("opengl32\glBegin", "uint", f[d[1]])
RegExMatch(d[2], "iO)^([2-4]V)([1-4]T)?(3N)?$", o)
p := 1
while (d[3].hasKey(p))
{
x := 1
if (o[x]="2V")
DllCall("opengl32\glVertex2f", "float", d[3,p], "float", d[3,p+1])
else if (o[x]="3V")
DllCall("opengl32\glVertex3f", "float", d[3,p], "float", d[3,p+1], "float", d[3,p+2])
else if (o[x]="4V")
DllCall("opengl32\glVertex3f", "float", d[3,p], "float", d[3,p+1], "float", d[3,p+2], "float", d[3,p+3])
p += (Substr(o[x], 1, 1)+0)
x += 1
if (Substr(o[x], 2, 1)="T")
{
if (o[x]="1T")
DllCall("opengl32\glTexCoord1f", "float", d[3,p])
if (o[x]="2T")
DllCall("opengl32\glTexCoord2f", "float", d[3,p], "float", d[3,p+1])
if (o[x]="3T")
DllCall("opengl32\glTexCoord3f", "float", d[3,p], "float", d[3,p+1], "float", d[3,p+2])
if (o[x]="4T")
DllCall("opengl32\glTexCoord3f", "float", d[3,p], "float", d[3,p+1], "float", d[3,p+2], "float", d[3,p+3])
p += (Substr(o[x], 1, 1)+0)
x += 1
}
if (Substr(o[x], 2, 1)="N")
{
if (o[x]="3N")
DllCall("opengl32\glNormal3f", "float", d[3,p], "float", d[3,p+1], "float", d[3,p+2])
p += (Substr(o[x], 1, 1)+0)
x += 1
}
}
DllCall("opengl32\glEnd")
}
DllCall("opengl32\glPopMatrix")
DllCall("opengl32\glEndList")
}
identity()
{
return this.transform.identity()
}
translate(p*)
{
return this.transform.translate(p*)
}
rotate(p*)
{
return this.transform.rotate(p*)
}
scale(p*)
{
return this.transform.scale(p*)
}
_add(vertcount, format, array, material=0)
{
if (!RegExMatch(format, "iO)^([2-4]V)([1-4]T)?(3N)?$"))
return -1
this.data.insert([vertcount, format, array, material])
this._update()
}
addPoints(format, array, material=0)
{
return this._add(1, format, array, material)
}
addLines(format, array, material=0)
{
return this._add(2, format, array, material)
}
addTriangles(format, array, material=0)
{
return this._add(3, format, array, material)
}
addQuads(format, array, material=0)
{
return this._add(4, format, array, material)
}
clear()
{
this.data := []
this._update()
}
_set(vertcount, format, array, material=0)
{
this.clear()
return this._add(vertcount, format, array, material)
}
setPoints(format, array, material=0)
{
return this._set(1, format, array, material)
}
setLines(format, array, material=0)
{
return this._set(2, format, array, material)
}
setTriangles(format, array, material=0)
{
return this._set(3, format, array, material)
}
setQuads(format, array, material=0)
{
return this._set(4, format, array, material)
}
}
class Texture
{
__new()
{
this.objType := "3D.Texture"
DllCall("opengl32\glGenTextures", "uint", 1, "uint*", tex)
this.tex := tex
this.filter(3)
}
__delete()
{
if (this.tex)
DllCall("opengl32\glDeleteTextures", "uint", 1, "uint*", this.tex)
}
load(filename, format="")
{
static t := {RGB:3, RGBA:4, L:0x1909, LA:0x190A, I:0x8049}
VarSetCapacity(bgpin, 20, 0)
NumPut(1, bgpin, 0, "int")
s := -3
if (DllCall("gdiplus\GdiplusStartup", "ptr*", gptoken, "ptr", &bgpin, "ptr", 0)=0)
{
s := -2
if (DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", filename, "ptr*", gpbm)=0)
{
e := DllCall("gdiplus\GdipGetImageWidth", "ptr", gpbm, "uint*", w)
e += DllCall("gdiplus\GdipGetImageHeight", "ptr", gpbm, "uint*", h)
e += DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", gpbm, "uint*", bmformat)
e += DllCall("gdiplus\GdipImageRotateFlip", "ptr", gpbm, "int", 6)
if (e=0)
{
s := -1
if (!format)
format := ((bmformat&0xf=4) ? "L" : "RGB") ((bmformat&0x000C0000) ? "A" : "")
VarSetCapacity(rc, 16, 0)
NumPut(w, rc, 8, "int")
NumPut(h, rc, 12, "int")
VarSetCapacity(bgpbmdata, 32, 0)
if (DllCall("gdiplus\GdipBitmapLockBits", "ptr", gpbm, "ptr", &rc, "uint", 0x0001, "int", 0x26200A, "ptr", &bgpbmdata)=0)
{
scan := NumGet(bgpbmdata, 16, "ptr")
DllCall("opengl32\glBindTexture", "int", 0x0DE1, "uint", this.tex)
DllCall("opengl32\glTexImage2D", "int", 0x0DE1, "int", 0, "int", (t[format]) ? t[format] : 4, "int", w, "int", h, "int", 0, "int", 0x80E1, "int", 0x1401, "ptr", scan)
DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", gpbm, "ptr", &bgpbmdata)
s := ""
}
}
DllCall("gdiplus\GdipDisposeImage", "ptr", gpbm)
}
DllCall("gdiplus\GdiplusShutdown", "ptr", gptoken)
}
return s
}
filter(level=3)
{
static f := {1:[0,0], 2:[0,1], 3:[1,1]}
DllCall("opengl32\glBindTexture", "int", 0x0DE1, "uint", this.tex)
DllCall("opengl32\glTexParameteri", "uint", 0x0DE1, "uint", 0x2801, "uint", 0x2600+(f[level,1]))
DllCall("opengl32\glTexParameteri", "uint", 0x0DE1, "uint", 0x2800, "uint", 0x2600+(f[level,2]))
}
}
class Material
{
__new()
{
this.objType := "3D.Material"
this.list := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.data := []
this.data.ambient := [0.2,0.2,0.2,1.0]
this.data.diffuse := [0.8,0.8,0.8,1.0]
this.data.specular := [0.0,0.0,0.0,1.0]
this.data.emission := [0.0,0.0,0.0,1.0]
this.data.shininess := 0
this.data.texture := 0
this._update()
}
__delete()
{
if (this.list)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
}
_glMaterial(n, clr)
{
VarSetCapacity(b, 16, 0)
NumPut(clr[1], b, 0, "float")
NumPut(clr[2], b, 4, "float")
NumPut(clr[3], b, 8, "float")
NumPut(clr[4], b, 12, "float")
DllCall("opengl32\glMaterialfv", "uint", 0x0408, "uint", n, "ptr", &b)
}
_update()
{
DllCall("opengl32\glNewList", "uint", this.list, "uint", 0x1300)
this._glMaterial(0x1200, this.data.ambient)
this._glMaterial(0x1201, this.data.diffuse)
this._glMaterial(0x1202, this.data.specular)
this._glMaterial(0x1600, this.data.emission)
DllCall("opengl32\glMaterialf", "uint", 0x0408, "uint", 0x1601, "float", this.data.shininess)
DllCall("opengl32\glBindTexture", "uint", 0x0DE1, "uint", this.data.texture.tex)
DllCall("opengl32\glEndList")
}
ambient(r=0.2, g=0.2, b=0.2, i=1)
{
this.data.ambient := [r,g,b,i]
this._update()
}
diffuse(r=0.8, g=0.8, b=0.8, i=1)
{
this.data.diffuse := [r,g,b,i]
this._update()
}
specular(r=0.0, g=0.0, b=0.0, i=1)
{
this.data.specular := [r,g,b,i]
this._update()
}
emission(r=0.0, g=0.0, b=0.0, i=1)
{
this.data.emission := [r,g,b,i]
this._update()
}
shininess(i=0)
{
this.data.shininess := i
this._update()
}
texture(texture)
{
this.data.texture := (texture.objType="3D.Texture") ? texture : 0
this._update()
}
}
class Light
{
__new()
{
this.objType := "3D.Light"
this.list := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.data := []
this.data.ambient := [0.0,0.0,0.0,1.0]
this.data.diffuse := [1.0,1.0,1.0,1.0]
this.data.specular := [0.0,0.0,0.0,1.0]
this.data.position := [0.0,0.0,1.0,0.0]
this.data.direction := [0.0,0.0,-1.0,0.0]
this._update()
}
__delete()
{
if (this.list)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
}
_glLight(n, clr)
{
VarSetCapacity(b, 16, 0)
NumPut(clr[1], b, 0, "float")
NumPut(clr[2], b, 4, "float")
NumPut(clr[3], b, 8, "float")
NumPut(clr[4], b, 12, "float")
DllCall("opengl32\glLightfv", "uint", 0x4000, "uint", n, "ptr", &b)
}
_update()
{
DllCall("opengl32\glNewList", "uint", this.list, "uint", 0x1300)
this._glLight(0x1200, this.data.ambient)
this._glLight(0x1201, this.data.diffuse)
this._glLight(0x1202, this.data.specular)
this._glLight(0x1203, this.data.position)
this._glLight(0x1204, this.data.direction)
DllCall("opengl32\glEndList")
}
ambient(r=0.0, g=0.0, b=0.0, i=1)
{
this.data.ambient := [r,g,b,i]
this._update()
}
diffuse(r=1.0, g=1.0, b=1.0, i=1)
{
this.data.diffuse := [r,g,b,i]
this._update()
}
specular(r=0.0, g=0.0, b=0.0, i=1)
{
this.data.specular := [r,g,b,i]
this._update()
}
position(x=0.0, y=0.0, z=1.0, w=0)
{
this.data.position := [x,y,z,w]
this._update()
}
direction(x=0.0, y=0.0, z=-1.0)
{
this.data.direction := [x,y,z,0.0]
this._update()
}
}
class Shader
{
__new()
{
this.objType := "3D.Shader"
if (!(h := 3D._glProc("glCreateProgramARB", "glCreateProgram")))
return -1
this.program := DllCall(h, "uint")
if (!(h := 3D._glProc("glCreateShaderARB", "glCreateShader")))
return -1
this.vertexObject := DllCall(h, "uint", 0x8B31, "uint")
this.fragmentObject := DllCall(h, "uint", 0x8B30, "uint")
}
_setSource(src, obj, outinfo="")
{
if (outinfo)
this[outinfo] := ""
if (!(h := 3D._glProc("glShaderSourceARB", "glShaderSource")))
return -1
DllCall(h, "uint", obj, "int", 1, "astr*", src, "ptr", 0)
if (!(h := 3D._glProc("glCompileShaderARB", "glCompileShader")))
return -1
DllCall(h, "uint", obj)
if (h := 3D._glProc("glGetShaderiv"))
{
DllCall(h, "uint", obj, "uint", 0x8B81, "int*", r)
if (!r)
{
DllCall(h, "uint", obj, "uint", 0x8B84, "int*", s)
if (!outinfo || !(h := 3D._glProc("glGetShaderInfoLog")))
return -2
VarSetCapacity(infob, s+2, 0)
DllCall(h, "uint", obj, "int", s, "int*", so, "ptr", &infob)
this[outinfo] := StrGet(&infob, "cp0")
return -2
}
}
if (!(h := 3D._glProc("glAttachObjectARB", "glAttachShader")))
return -1
DllCall(h, "uint", this.program, "uint", this.vertexObject)
DllCall(h, "uint", this.program, "uint", this.fragmentObject)
if (!(h := 3D._glProc("glLinkProgramARB", "glLinkProgram")))
return -1
DllCall(h, "uint", this.program)
}
vertex(src)
{
return this._setSource(src, this.vertexObject, "vertexInfo")
}
fragment(src)
{
return this._setSource(src, this.fragmentObject, "fragmentInfo")
}
}
_glProc(p*)
{
for k,v in p
{
if (ptr := DllCall("opengl32\wglGetProcAddress", "astr", v, "ptr"))
return ptr
}
}
}
Hab das nachfolgende Projekt mal auf Eis gelegt...
Möglicherweise kannst du ja was davon verwenden.
In TODO hab ich vermerkt was mir noch fehlt.
Was mir noch auf die Schnelle einfällt ist, dass ich die Kameraklasse nicht richtig getestet habe.
Und ein problem mit Licht und Materialien -> die ich in nem Shader berechnen wollte für multiple Lichter (mehr als die 8 die meine Graka berechnen würde).
Alternativ könnte man auch den Lichtshader weg lassen und das Hauptlicht (zB. Sonne) und die dem Model nächsten 7 Lichter verwenden (Jede Graka mit OpenGL unterstützt min. 8 bis max. 32).
Ansonsten sollte alles relativ performant sein, da alle Objekte Displaylisten verwenden.
Geht zwar etwas auf den Grafikspeicher, aber Texturen sind ohnehin schlimmer für den Speicher :D .
Die Idee ist, wenn sich kein Model, Textur, Kamera, ... in der Szene ändert reicht ein einziger Aufruf einer Displayliste die die komplette Szene zeichnet.
Dann noch wglMakeCurrent, SwapBuffers und glClear... sind nur 4 DllCalls.
Btw. diese Engine war auch dafür gedacht, dass mehrere Monitore in Vollbild bzw. mehrere Fenster verwendet werden können.
Daher die umständliche Initialisierung der Renderer-Klasse, die untereinander die Renderkontexte (Texturen, Displaylisten, etc.) teilen.
[code=autohotkey file=Script.ahk]; TODO:
;============================
; - Multiple lights
; - Shaders (delete, uniform)
; - Model loading
; - Bumpmaps
; - Fog
; - Blending
#NoEnv
SetWorkingDir, % A_ScriptDir
SetBatchLines, -1
; Init GUI
Gui, +LastFound
Gui, show, w640 h480, AHK 3D Engine
; Init 3D stuff
renderer := new 3D.Renderer(WinExist())
if (!IsObject(renderer))
MsgBox, % "ERROR: Can't create renderer (" renderer ")"
viewport := new 3D.Viewport(renderer)
camera := new 3D.Camera()
camera.perspective(90, viewport, 0.1, 100)
; Load a texture
tex := new 3D.Texture()
tex.load("test.jpg")
; Create a material
mat := new 3D.Material()
mat.texture(tex)
; Create a cube model
model := new 3D.Model()
a := 0.5
b := -0.5
;pos: x,y,z
;tex: | | | x,y
;normal: | | | | | x,y,z
; | | | | | | | |
cube := [a,a,a, 0,0, 0,0,1, b,a,a, 1,0, 0,0,1, b,b,a, 1,1, 0,0,1, a,b,a, 0,1, 0,0,1 ;front
, a,a,a, 0,0, 1,0,0, a,b,a, 1,0, 1,0,0, a,b,b, 1,1, 1,0,0, a,a,b, 0,1, 1,0,0 ;right
, a,a,a, 0,0, 0,1,0, b,a,a, 1,0, 0,1,0, b,a,b, 1,1, 0,1,0, a,a,b, 0,1, 0,1,0 ;top
, a,a,b, 0,0, 0,0,-1, b,a,b, 1,0, 0,0,-1, b,b,b, 1,1, 0,0,-1, a,b,b, 0,1, 0,0,-1 ;back
, b,a,a, 0,0, -1,0,0, b,b,a, 1,0, -1,0,0, b,b,b, 1,1, -1,0,0, b,a,b, 0,1, -1,0,0 ;left
, a,b,a, 0,0, 0,-1,0, b,b,a, 1,0, 0,-1,0, b,b,b, 1,1, 0,-1,0, a,b,b, 0,1, 0,-1,0] ;bottom
model.setQuads("3V2T3N", cube, mat)
model.translate(0, 0, -1.2)
light := new 3D.Light()
light.ambient(0.5, 0.5, 0.5, 1.0)
light.diffuse(1.0, 1.0, 1.0, 1.0)
light.specular(0.2, 0.2, 0.2, 1.0)
light.position(0.0, 0.5, 0.0, 1.0)
shader := new 3D.Shader()
shader.vertex("
(Join`n
void main(void)
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
}
)")
shader.fragment("
(Join`n
uniform sampler2D Texture0;
void main(void)
{
gl_FragColor = texture2D(Texture0, vec2(gl_TexCoord[0]));
}
)")
scene := new 3D.Scene()
scene.addChild(light)
scene.addChild(model)
scene.addChild(shader)
stopped := 0
SetTimer, timer, 30
return
timer:
if (!stopped && (GetKeyState("up") || GetKeyState("down") || GetKeyState("left") || GetKeyState("right")))
stopped := 1
if (!stopped)
model.rotate(1, 0.94, 1.71, 0.26)
if (stopped && GetKeyState("up"))
model.rotate(1, 1, 0, 0)
if (stopped && GetKeyState("down"))
model.rotate(-1, 1, 0, 0)
if (stopped && GetKeyState("left"))
model.rotate(1, 0, 1, 0)
if (stopped && GetKeyState("right"))
model.rotate(-1, 0, 1, 0)
renderer.render(scene, viewport, camera)
return
class 3D
{
static hOpenGL := DllCall("LoadLibrary", "str", "opengl32", "ptr")
static hGdiPlus := DllCall("LoadLibrary", "str", "gdiplus", "ptr")
class Renderer
{
static shareRenderer := 0
__new(wnd)
{
this.objType := "3D.Renderer"
if (!isObject(3D.Renderer.shareRenderer) && wnd!="_share")
3D.Renderer.shareRenderer := new 3D.Renderer("_share")
if (wnd=="_share")
{
lf := WinExist()
Gui, _3D_Renderer_ShareRenderer: +LastFound
Gui, _3D_Renderer_ShareRenderer:show, hide
wnd := WinExist()
WinExist("ahk_id " lf)
}
else if (!isObject(3D.Renderer.shareRenderer))
return 3D.Renderer.shareRenderer
this.hWnd := (isObject(wnd) && wnd.hasKey("hWnd")) ? wnd.hWnd : wnd
if (!(this.hDC := DllCall("GetDC", "ptr", this.hWnd, "ptr")))
return -3 ; ERROR: Can't get the device context
VarSetCapacity(pfd, 40, 0)
NumPut(40, pfd, 0, "ushort")
NumPut(1, pfd, 2, "ushort")
NumPut(0x25, pfd, 4, "uint")
NumPut(32, pfd, 9, "uchar")
NumPut(16, pfd, 23, "uchar")
if (!(pf := DllCall("ChoosePixelFormat", "ptr", this.hDC, "ptr", &pfd, "int")))
return -4 ; ERROR: Can't choose the pixel format
if (!DllCall("SetPixelFormat", "ptr", this.hDC, "int", pf, "ptr", &pfd))
return -5 ; ERROR: Can't select the pixel format
if (!(this.hRC := DllCall("opengl32\wglCreateContext", "ptr", this.hDC, "ptr")))
return -6 ; ERROR: Can't create the render context
if (!DllCall("opengl32\wglMakeCurrent", "ptr", this.hDC, "ptr", this.hRC))
return -7 ; ERROR: Can't activate the render context
if (IsObject(3D.Renderer.shareRenderer) && !DllCall("opengl32\wglShareLists", "ptr", this.hRC, "ptr", 3D.Renderer.shareRenderer.hRC))
return -8 ; ERROR: Can't share lists between render context's
DllCall("opengl32\glShadeModel", "uint", 0x1D01)
DllCall("opengl32\glHint", "uint", 0x0C50, "uint", 0x1102)
DllCall("opengl32\glEnable", "uint", 0x0DE1) ;texture
DllCall("opengl32\glEnable", "uint", 0x4000) ;light
DllCall("opengl32\glDepthFunc", "uint", 0x0203)
DllCall("SwapBuffers", "ptr", this.hDC)
}
__delete()
{
if (this.hRC)
{
DllCall("opengl32\wglMakeCurrent", "ptr", 0, "ptr", 0)
DllCall("opengl32\wglDeleteContext", "ptr", this.hRC)
}
if (this.hDC)
DllCall("ReleaseDC", "ptr", this.hWnd, "ptr", this.hDC)
}
render(scene, viewport, camera)
{
DllCall("opengl32\wglMakeCurrent", "ptr", this.hDC, "ptr", this.hRC)
DllCall("opengl32\glViewport", "int", viewport.x, "int", viewport.y, "int", viewport.width, "int", viewport.height)
DllCall("opengl32\glClear", "uint", 0x00004100)
DllCall("opengl32\glCallList", "uint", camera.list)
DllCall("opengl32\glCallList", "uint", scene.list)
DllCall("SwapBuffers", "ptr", this.hDC)
}
}
class Viewport
{
__new(renderer=0)
{
this.objType := "3D.Viewport"
this.x := this.y := 0
this.width := this.height := 512
if (renderer.objType="3D.Renderer")
this.renderer(renderer)
}
renderer(renderer)
{
VarSetCapacity(rc, 16, 0)
DllCall("GetClientRect", "ptr", renderer.hWnd, "ptr", &rc)
this.width := NumGet(rc, 8, "int")
this.height := NumGet(rc, 12, "int")
}
setViewport(x=0, y=0, width=512, height=512)
{
this.x := x
this.y := y
this.width := width
this.height := height
}
}
class Scene
{
__new()
{
this.list := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.shaderList := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.childs := []
this.shaders := []
}
__delete()
{
if (this.list)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
if (this.shaderList)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
}
_update()
{
glUseProgram := 3D._glProc("glUseProgramObjectARB", "glUseProgram")
if (glUseProgram)
{
DllCall("opengl32\glNewList", "uint", this.shaderList, "uint", 0x1300)
for sk,sv in this.shaders
DllCall(glUseProgram, "uint", sv.program)
DllCall("opengl32\glEndList")
}
DllCall("opengl32\glNewList", "uint", this.list, "uint", 0x1300)
for k,v in this.childs
{
DllCall("opengl32\glCallList", "uint", this.shaderList)
DllCall("opengl32\glCallList", "uint", v.list)
if (glUseProgram)
DllCall(glUseProgram, "uint", 0)
}
DllCall("opengl32\glEndList")
}
addChild(obj)
{
if (obj.objType="3D.Model" || obj.objType="3D.Light")
{
this.childs[Object(obj)] := obj
this._update()
}
if (obj.objType="3D.Shader")
{
this.shaders[Object(obj)] := obj
this._update()
}
}
}
class Transform
{
__new()
{
this.objType := "3D.Transform"
this.ptr := DllCall("HeapAlloc", "ptr", DllCall("GetProcessHeap", "ptr"), "uint", 0x8, "ptr", 64, "ptr")
this.list := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.identity()
this._update()
}
_update()
{
DllCall("opengl32\glNewList", "uint", this.list, "uint", 0x1300)
DllCall("opengl32\glMultMatrixf", "ptr", this.ptr)
DllCall("opengl32\glEndList")
}
__delete()
{
if (this.ptr)
DllCall("HeapFree", "ptr", DllCall("GetProcessHeap", "ptr"), "uint", 0, "ptr", this.ptr)
if (this.list)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
}
_glTransform(p*)
{
DllCall("opengl32\glMatrixMode", "uint", 0x1700)
DllCall("opengl32\glLoadMatrixf", "ptr", this.ptr)
DllCall(p*)
DllCall("opengl32\glGetFloatv", "uint", 0x0BA6, "ptr", this.ptr)
this._update()
}
identity()
{
return this._glTransform("opengl32\glLoadIdentity")
}
translate(x, y, z)
{
return this._glTransform("opengl32\glTranslatef", "float", x, "float", y, "float", z)
}
rotate(angle, x, y, z)
{
return this._glTransform("opengl32\glRotatef", "float", angle, "float", x, "float", y, "float", z)
}
scale(x, y, z)
{
return this._glTransform("opengl32\glScalef", "float", x, "float", y, "float", z)
}
}
class Camera
{
__new()
{
this.objType := "3D.Camera"
this.transform := new 3D.Transform()
this.list := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.depthTest := "_?"
}
__delete()
{
if (this.list)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
}
identity()
{
return this.transform.identity()
}
translate(x, y, z)
{
return this.transform.translate(-x, -y, -z)
}
rotate(angle, x, y, z)
{
return this.transform.rotate(angle, -x, -y, -z)
}
scale(x, y, z)
{
return this.transform.scale(-x, -y, -z)
}
_glCamera(p*)
{
DllCall("opengl32\glNewList", "uint", this.list, "uint", 0x1300)
DllCall("opengl32\glMatrixMode", "uint", 0x1701)
DllCall("opengl32\glLoadIdentity")
DllCall(p*)
DllCall("opengl32\glMatrixMode", "uint", 0x1700)
DllCall("opengl32\glLoadIdentity")
DllCall("opengl32\glCallList", "uint", this.transform.list)
DllCall((this.depthTest) ? "opengl32\glEnable" : "opengl32\glDisable", "uint", 0x0B71)
DllCall("opengl32\glEndList")
}
ortho(left, right, bottom, top, near, far)
{
if (this.depthTest=="_?")
this.depthTest := 0
this._glCamera("opengl32\glOrtho", "double", left, "double", right, "double", bottom, "double", top, "double", near, "double", far)
}
frustum(left, right, bottom, top, near, far)
{
if (this.depthTest=="_?")
this.depthTest := 1
this._glCamera("opengl32\glFrustum", "double", left, "double", right, "double", bottom, "double", top, "double", near, "double", far)
}
perspective(fov, aspect, near, far)
{
static pi := 3.1415926535897
aspect := (aspect.hasKey("objType") && aspect.objType="3D.Viewport") ? aspect.width/aspect.height : aspect
h := tan(fov/360*pi)*near
w := h*aspect
this.frustum(-w, w, -h, h, near, far)
}
}
class Model
{
__new()
{
this.objType := "3D.Model"
this.transform := new 3D.Transform()
this.list := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.data := []
}
__delete()
{
if (this.list)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
}
_update()
{
static f := {1:0, 2:1, 3:4, 4:7}
DllCall("opengl32\glNewList", "uint", this.list, "uint", 0x1300)
DllCall("opengl32\glPushMatrix")
DllCall("opengl32\glCallList", "uint", this.transform.list)
for i, d in this.data
{
if (d[4].objType!="3D.Material")
DllCall("opengl32\glDisable", "uint", 0x0B50)
if (d[4].objType="3D.Material")
{
DllCall("opengl32\glEnable", "uint", 0x0B50)
DllCall("opengl32\glCallList", "uint", d[4])
}
else
DllCall("opengl32\glBindTexture", "uint", 0x0DE1, "uint", 0)
DllCall("opengl32\glBegin", "uint", f[d[1]])
RegExMatch(d[2], "iO)^([2-4]V)([1-4]T)?(3N)?$", o)
p := 1
while (d[3].hasKey(p))
{
x := 1
if (o[x]="2V")
DllCall("opengl32\glVertex2f", "float", d[3,p], "float", d[3,p+1])
else if (o[x]="3V")
DllCall("opengl32\glVertex3f", "float", d[3,p], "float", d[3,p+1], "float", d[3,p+2])
else if (o[x]="4V")
DllCall("opengl32\glVertex3f", "float", d[3,p], "float", d[3,p+1], "float", d[3,p+2], "float", d[3,p+3])
p += (Substr(o[x], 1, 1)+0)
x += 1
if (Substr(o[x], 2, 1)="T")
{
if (o[x]="1T")
DllCall("opengl32\glTexCoord1f", "float", d[3,p])
if (o[x]="2T")
DllCall("opengl32\glTexCoord2f", "float", d[3,p], "float", d[3,p+1])
if (o[x]="3T")
DllCall("opengl32\glTexCoord3f", "float", d[3,p], "float", d[3,p+1], "float", d[3,p+2])
if (o[x]="4T")
DllCall("opengl32\glTexCoord3f", "float", d[3,p], "float", d[3,p+1], "float", d[3,p+2], "float", d[3,p+3])
p += (Substr(o[x], 1, 1)+0)
x += 1
}
if (Substr(o[x], 2, 1)="N")
{
if (o[x]="3N")
DllCall("opengl32\glNormal3f", "float", d[3,p], "float", d[3,p+1], "float", d[3,p+2])
p += (Substr(o[x], 1, 1)+0)
x += 1
}
}
DllCall("opengl32\glEnd")
}
DllCall("opengl32\glPopMatrix")
DllCall("opengl32\glEndList")
}
identity()
{
return this.transform.identity()
}
translate(p*)
{
return this.transform.translate(p*)
}
rotate(p*)
{
return this.transform.rotate(p*)
}
scale(p*)
{
return this.transform.scale(p*)
}
_add(vertcount, format, array, material=0)
{
if (!RegExMatch(format, "iO)^([2-4]V)([1-4]T)?(3N)?$"))
return -1
this.data.insert([vertcount, format, array, material])
this._update()
}
addPoints(format, array, material=0)
{
return this._add(1, format, array, material)
}
addLines(format, array, material=0)
{
return this._add(2, format, array, material)
}
addTriangles(format, array, material=0)
{
return this._add(3, format, array, material)
}
addQuads(format, array, material=0)
{
return this._add(4, format, array, material)
}
clear()
{
this.data := []
this._update()
}
_set(vertcount, format, array, material=0)
{
this.clear()
return this._add(vertcount, format, array, material)
}
setPoints(format, array, material=0)
{
return this._set(1, format, array, material)
}
setLines(format, array, material=0)
{
return this._set(2, format, array, material)
}
setTriangles(format, array, material=0)
{
return this._set(3, format, array, material)
}
setQuads(format, array, material=0)
{
return this._set(4, format, array, material)
}
}
class Texture
{
__new()
{
this.objType := "3D.Texture"
DllCall("opengl32\glGenTextures", "uint", 1, "uint*", tex)
this.tex := tex
this.filter(3)
}
__delete()
{
if (this.tex)
DllCall("opengl32\glDeleteTextures", "uint", 1, "uint*", this.tex)
}
load(filename, format="")
{
static t := {RGB:3, RGBA:4, L:0x1909, LA:0x190A, I:0x8049}
VarSetCapacity(bgpin, 20, 0)
NumPut(1, bgpin, 0, "int")
s := -3
if (DllCall("gdiplus\GdiplusStartup", "ptr*", gptoken, "ptr", &bgpin, "ptr", 0)=0)
{
s := -2
if (DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", filename, "ptr*", gpbm)=0)
{
e := DllCall("gdiplus\GdipGetImageWidth", "ptr", gpbm, "uint*", w)
e += DllCall("gdiplus\GdipGetImageHeight", "ptr", gpbm, "uint*", h)
e += DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", gpbm, "uint*", bmformat)
e += DllCall("gdiplus\GdipImageRotateFlip", "ptr", gpbm, "int", 6)
if (e=0)
{
s := -1
if (!format)
format := ((bmformat&0xf=4) ? "L" : "RGB") ((bmformat&0x000C0000) ? "A" : "")
VarSetCapacity(rc, 16, 0)
NumPut(w, rc, 8, "int")
NumPut(h, rc, 12, "int")
VarSetCapacity(bgpbmdata, 32, 0)
if (DllCall("gdiplus\GdipBitmapLockBits", "ptr", gpbm, "ptr", &rc, "uint", 0x0001, "int", 0x26200A, "ptr", &bgpbmdata)=0)
{
scan := NumGet(bgpbmdata, 16, "ptr")
DllCall("opengl32\glBindTexture", "int", 0x0DE1, "uint", this.tex)
DllCall("opengl32\glTexImage2D", "int", 0x0DE1, "int", 0, "int", (t[format]) ? t[format] : 4, "int", w, "int", h, "int", 0, "int", 0x80E1, "int", 0x1401, "ptr", scan)
DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", gpbm, "ptr", &bgpbmdata)
s := ""
}
}
DllCall("gdiplus\GdipDisposeImage", "ptr", gpbm)
}
DllCall("gdiplus\GdiplusShutdown", "ptr", gptoken)
}
return s
}
filter(level=3)
{
static f := {1:[0,0], 2:[0,1], 3:[1,1]}
DllCall("opengl32\glBindTexture", "int", 0x0DE1, "uint", this.tex)
DllCall("opengl32\glTexParameteri", "uint", 0x0DE1, "uint", 0x2801, "uint", 0x2600+(f[level,1]))
DllCall("opengl32\glTexParameteri", "uint", 0x0DE1, "uint", 0x2800, "uint", 0x2600+(f[level,2]))
}
}
class Material
{
__new()
{
this.objType := "3D.Material"
this.list := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.data := []
this.data.ambient := [0.2,0.2,0.2,1.0]
this.data.diffuse := [0.8,0.8,0.8,1.0]
this.data.specular := [0.0,0.0,0.0,1.0]
this.data.emission := [0.0,0.0,0.0,1.0]
this.data.shininess := 0
this.data.texture := 0
this._update()
}
__delete()
{
if (this.list)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
}
_glMaterial(n, clr)
{
VarSetCapacity(b, 16, 0)
NumPut(clr[1], b, 0, "float")
NumPut(clr[2], b, 4, "float")
NumPut(clr[3], b, 8, "float")
NumPut(clr[4], b, 12, "float")
DllCall("opengl32\glMaterialfv", "uint", 0x0408, "uint", n, "ptr", &b)
}
_update()
{
DllCall("opengl32\glNewList", "uint", this.list, "uint", 0x1300)
this._glMaterial(0x1200, this.data.ambient)
this._glMaterial(0x1201, this.data.diffuse)
this._glMaterial(0x1202, this.data.specular)
this._glMaterial(0x1600, this.data.emission)
DllCall("opengl32\glMaterialf", "uint", 0x0408, "uint", 0x1601, "float", this.data.shininess)
DllCall("opengl32\glBindTexture", "uint", 0x0DE1, "uint", this.data.texture.tex)
DllCall("opengl32\glEndList")
}
ambient(r=0.2, g=0.2, b=0.2, i=1)
{
this.data.ambient := [r,g,b,i]
this._update()
}
diffuse(r=0.8, g=0.8, b=0.8, i=1)
{
this.data.diffuse := [r,g,b,i]
this._update()
}
specular(r=0.0, g=0.0, b=0.0, i=1)
{
this.data.specular := [r,g,b,i]
this._update()
}
emission(r=0.0, g=0.0, b=0.0, i=1)
{
this.data.emission := [r,g,b,i]
this._update()
}
shininess(i=0)
{
this.data.shininess := i
this._update()
}
texture(texture)
{
this.data.texture := (texture.objType="3D.Texture") ? texture : 0
this._update()
}
}
class Light
{
__new()
{
this.objType := "3D.Light"
this.list := DllCall("opengl32\glGenLists", "uint", 1, "uint")
this.data := []
this.data.ambient := [0.0,0.0,0.0,1.0]
this.data.diffuse := [1.0,1.0,1.0,1.0]
this.data.specular := [0.0,0.0,0.0,1.0]
this.data.position := [0.0,0.0,1.0,0.0]
this.data.direction := [0.0,0.0,-1.0,0.0]
this._update()
}
__delete()
{
if (this.list)
DllCall("opengl32\glFreeLists", "uint", this.list, "uint", 1)
}
_glLight(n, clr)
{
VarSetCapacity(b, 16, 0)
NumPut(clr[1], b, 0, "float")
NumPut(clr[2], b, 4, "float")
NumPut(clr[3], b, 8, "float")
NumPut(clr[4], b, 12, "float")
DllCall("opengl32\glLightfv", "uint", 0x4000, "uint", n, "ptr", &b)
}
_update()
{
DllCall("opengl32\glNewList", "uint", this.list, "uint", 0x1300)
this._glLight(0x1200, this.data.ambient)
this._glLight(0x1201, this.data.diffuse)
this._glLight(0x1202, this.data.specular)
this._glLight(0x1203, this.data.position)
this._glLight(0x1204, this.data.direction)
DllCall("opengl32\glEndList")
}
ambient(r=0.0, g=0.0, b=0.0, i=1)
{
this.data.ambient := [r,g,b,i]
this._update()
}
diffuse(r=1.0, g=1.0, b=1.0, i=1)
{
this.data.diffuse := [r,g,b,i]
this._update()
}
specular(r=0.0, g=0.0, b=0.0, i=1)
{
this.data.specular := [r,g,b,i]
this._update()
}
position(x=0.0, y=0.0, z=1.0, w=0)
{
this.data.position := [x,y,z,w]
this._update()
}
direction(x=0.0, y=0.0, z=-1.0)
{
this.data.direction := [x,y,z,0.0]
this._update()
}
}
class Shader
{
__new()
{
this.objType := "3D.Shader"
if (!(h := 3D._glProc("glCreateProgramARB", "glCreateProgram")))
return -1
this.program := DllCall(h, "uint")
if (!(h := 3D._glProc("glCreateShaderARB", "glCreateShader")))
return -1
this.vertexObject := DllCall(h, "uint", 0x8B31, "uint")
this.fragmentObject := DllCall(h, "uint", 0x8B30, "uint")
}
_setSource(src, obj, outinfo="")
{
if (outinfo)
this[outinfo] := ""
if (!(h := 3D._glProc("glShaderSourceARB", "glShaderSource")))
return -1
DllCall(h, "uint", obj, "int", 1, "astr*", src, "ptr", 0)
if (!(h := 3D._glProc("glCompileShaderARB", "glCompileShader")))
return -1
DllCall(h, "uint", obj)
if (h := 3D._glProc("glGetShaderiv"))
{
DllCall(h, "uint", obj, "uint", 0x8B81, "int*", r)
if (!r)
{
DllCall(h, "uint", obj, "uint", 0x8B84, "int*", s)
if (!outinfo || !(h := 3D._glProc("glGetShaderInfoLog")))
return -2
VarSetCapacity(infob, s+2, 0)
DllCall(h, "uint", obj, "int", s, "int*", so, "ptr", &infob)
this[outinfo] := StrGet(&infob, "cp0")
return -2
}
}
if (!(h := 3D._glProc("glAttachObjectARB", "glAttachShader")))
return -1
DllCall(h, "uint", this.program, "uint", this.vertexObject)
DllCall(h, "uint", this.program, "uint", this.fragmentObject)
if (!(h := 3D._glProc("glLinkProgramARB", "glLinkProgram")))
return -1
DllCall(h, "uint", this.program)
}
vertex(src)
{
return this._setSource(src, this.vertexObject, "vertexInfo")
}
fragment(src)
{
return this._setSource(src, this.fragmentObject, "fragmentInfo")
}
}
_glProc(p*)
{
for k,v in p
{
if (ptr := DllCall("opengl32\wglGetProcAddress", "astr", v, "ptr"))
return ptr
}
}
}
[/code]