Hard Light Productions Forums

Modding, Mission Design, and Coding => The Scripting Workshop => Topic started by: Nuke on February 07, 2007, 10:56:49 am

Title: luaSDL / nuke makes a 3d engine
Post by: Nuke on February 07, 2007, 10:56:49 am
ok, i was screwing around with my scripting table, and got fed up with having to waith a couple minutes to load the game each time i wanted to check something. so i went looking for a stand alone imnterpreter so i could test some math functions i was writing. anyway i came across this (http://luaforge.net/frs/download.php/2126/LuaSDL-win32-0.3.2.zip)

after an hour of pulling out hair i got a screen to render stuff. so i took my point rotation functions and some other stuff i was working on and made a cute little 3d graphics engine, well sort of :D you can download the interpreter and play with my attached script. with all the sdl calls i dont thing freespace would like it.

then theres the matter of sdl librarys, think maybe they would perhaps do anything for the scripting system, or would it just be a redundant waste of time :D

btw to get my thingy to work stick the lua file into the root directory of the interpreter (be sure to overwrite the demo one that comes with the interpreter). keypad does everything, del exits.

[attachment deleted by admin]
Title: Re: luaSDL / nuke makes a 3d engine
Post by: Bobboau on February 07, 2007, 08:18:47 pm
wmc should consiter reloading the scripting table every time the main windo gets maximized.
Title: Re: luaSDL / nuke makes a 3d engine
Post by: WMCoolmon on February 09, 2007, 01:20:26 am
Possibly in debug builds, but not in release builds. You'd get parse errors every time the window was maximized, which wouldn't exactly be very helpful to someone just trying to play the game. Plus _any_ errors would force window minimization (at least at this point) and you'd get caught in an infinite loop.

If/when I put support for the scripting table into the scripting system, I could put in some kind of refresh() command or something. (That's another mind-bending activity, cause you'd probably be calling the refresh command in the scripting table to refresh the scripting table....but as long as the lua maintains the current execution thread while it changes all the table values to Something Else, I think it should be OK, as long as garbage collection is triggered as well so it isn't a massive memory leak.
Title: Re: luaSDL / nuke makes a 3d engine
Post by: Nuke on February 14, 2007, 12:18:38 pm
well i updated it a little. now it has arbitrary axis rotation, linear neutonian physics (rotations use no physics), joystick support, and of course a laser. :D

be sure to run it in that luaSDL interpreter and not in freespace. it can run in freespace with some modifications but youre gonna need to use some different imput, like mousejoy(), change all the vec_3d()s to ba.createVector()s and drawline() with gr.drawLine() and stuff like that.

Code: [Select]
-------------------------
-----init-----screen-----
-------------------------


SDL = SDL
SDL.SDL_Init(SDL.SDL_INIT_EVERYTHING)
screen = SDL.SDL_SetVideoMode(800, 600, 32, 0)
info = SDL.SDL_GetVideoInfo()

w,h = info.current_w, info.current_h
cx,cy = w/2,h/2

rect = SDL.SDL_Rect_local()
rect.x, rect.y = 0,0
rect.w, rect.h = w,h
grey = SDL.SDL_MapRGB(screen.format, 0x80, 0x80, 0x80)
blue = SDL.SDL_MapRGB(screen.format, 0x00, 0x00, 0x80)


---------------------------------------------
-----end init screen-----start type defs-----
---------------------------------------------


vec_2d = function(xy,ey)
local v = {}

if getmetatable(xy) == vec_2d_mt then
v.x = xy.x
v.y = xy.y
elseif type(xy) == 'table' then
v.x = xy[1]
v.y = xy[2]
elseif type(xy) == 'number' and type(ey) == 'number' then
v.x, v.y = xy, ey
else
v.x, v.y = 0, 0
end

setmetatable(v, vec_2d_mt)

return v
end


vec_2d_mt = {
__add = function(v1,v2) return vec_2d(v1.x + v2.x, v1.y + v2.y) end,

__sub = function(v1,v2) return vec_2d(v1.x - v2.x, v1.y - v2.y) end,

__unm = function(v) return vec_2d(-v.x,-v.y) end,

__mul = function(v1,v2)
if type(v1) == 'number' then
return vec_2d(v1 * v2.x, v1 * v2.y)
elseif type(v2) == 'number' then
return vec_2d(v1.x * v2, v1.y * v2)
else
return vec_2d(v1.x * v2.x, v1.y * v2.y)
end
end,

__div = function(v1,v2)
if type(v1) == 'number' then
return vec_2d(v1 / v2.x, v1 / v2.y)
elseif type(v2) == 'number' then
return vec_2d(v1.x / v2, v1.y / v2)
else
return vec_2d(v1.x / v2.x, v1.y / v2.y)
end
end,

__concat = function(v,r)
local nx = v.x * math.cos(r) - v.y * math.sin(r)
local ny = v.x * math.sin(r) + v.y * math.cos(r)
v = vec_2d( nx, ny )
return v
end,

__index = function(v,key)
if key == 'norm' then
local len = math.sqrt( v.x^2 + v.y^2 )
v.norm = vec_2d( v.x / len, v.y / len )
return v.norm
end
end
}


vec_3d = function(xyz,ey,ez)
local v = {}

if getmetatable(xyz) == vec_3d_mt then
v.x = xyz.x
v.y = xyz.y
v.z = xyz.z
elseif type(xyz) == 'table' then
v.x = xyz[1]
v.y = xyz[2]
v.z = xyz[3]
elseif type(xyz) == 'number' and type(ey) == 'number' and type(ez) == 'number' then
v.x, v.y, v.z = xyz, ey, ez
else
v.x, v.y, v.z = 0, 0, 0
end

setmetatable(v, vec_3d_mt)

return v
end


vec_3d_mt = {
__add = function(v1,v2) return vec_3d(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z) end,

__sub = function(v1,v2) return vec_3d(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z) end,

__unm = function(v) return vec_3d(-v.x,-v.y,-v.z) end,

__mul = function(v1,v2)
if type(v1) == 'number' then
return vec_3d(v1 * v2.x, v1 * v2.y, v1 * v2.z)
elseif type(v2) == 'number' then
return vec_3d(v1.x * v2, v1.y * v2, v1.z * v2)
else
return vec_3d(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z)
end
end,

__div = function(v1,v2)
if type(v1) == 'number' then
return vec_3d(v1 / v2.x, v1 / v2.y, v1 / v2.z)
elseif type(v2) == 'number' then
return vec_3d(v1.x / v2, v1.y / v2, v1.z / v2)
else
return vec_3d(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z)
end
end,

__index = function(v,key)
if key == 'norm' then
local len = math.sqrt( v.x^2 + v.y^2 + v.z^2 )
v.norm = vec_3d( v.x / len, v.y / len, v.z / len )
return v.norm
end
end
}


---------------------------------------
-----end type defs-----start maths-----
---------------------------------------


normalize_2d = function(v)
local len  = math.sqrt( math.abs( v[1]*v[1] ) + math.abs( v[2]*v[2] ) )
v[1], v[2] = v[1] / len, v[2] / len
end


normalize_3d = function(v)
local len  = math.sqrt( math.abs( v[1]*v[1] ) + math.abs( v[2]*v[2] ) + math.abs( v[3]*v[3] ) )
v[1], v[2], v[3] = v[1] / len, v[2] / len, v[3] / len
end


multmat = function(mat1,mat2) --multiply a couple 3x3 matricies
local mat3 = {}

mat3[1] = (mat1[1] * mat2[1]) + (mat1[2] * mat2[4]) + (mat1[3] * mat2[7])
mat3[2] = (mat1[1] * mat2[2]) + (mat1[2] * mat2[5]) + (mat1[3] * mat2[8])
mat3[3] = (mat1[1] * mat2[3]) + (mat1[2] * mat2[6]) + (mat1[3] * mat2[9])
mat3[4] = (mat1[4] * mat2[1]) + (mat1[5] * mat2[4]) + (mat1[6] * mat2[7])
mat3[5] = (mat1[4] * mat2[2]) + (mat1[5] * mat2[5]) + (mat1[6] * mat2[8])
mat3[6] = (mat1[4] * mat2[3]) + (mat1[5] * mat2[6]) + (mat1[6] * mat2[9])
mat3[7] = (mat1[7] * mat2[1]) + (mat1[8] * mat2[4]) + (mat1[9] * mat2[7])
mat3[8] = (mat1[7] * mat2[2]) + (mat1[8] * mat2[5]) + (mat1[9] * mat2[8])
mat3[9] = (mat1[7] * mat2[3]) + (mat1[8] * mat2[6]) + (mat1[9] * mat2[9])

return mat3
end


matxvec = function(mat,vec) --multiply a vextor by a matrix
local x = (mat[1] * vec[1]) + (mat[2] * vec[2]) + (mat[3] * vec[3])
local y = (mat[4] * vec[1]) + (mat[5] * vec[2]) + (mat[6] * vec[3])
local z = (mat[7] * vec[1]) + (mat[8] * vec[2]) + (mat[9] * vec[3])

vec[1],vec[2],vec[3] = x,y,z

return vec
end


rotnorm = function(norm,angs) --rotates a normal, in theory
local matx = {1,0,0,0,1,0,0,0,1}
local maty = {1,0,0,0,1,0,0,0,1} --create 3x3 matrix arrays for xyz and fill it in with an identity matrix
local matz = {1,0,0,0,1,0,0,0,1}

matx[5] = math.cos(angs[1])
matx[6] = math.sin(angs[1])
matx[8] = -math.sin(angs[1])
matx[9] = math.cos(angs[1])

maty[1] = math.cos(angs[2])
maty[3] = -math.sin(angs[2]) --fill in the nessicary parts of the matrix for each axis
maty[7] = math.sin(angs[2])
maty[9] = math.cos(angs[2])

matz[1] = math.cos(angs[3])
matz[2] = math.sin(angs[3])
matz[4] = -math.sin(angs[3])
matz[5] = math.cos(angs[3])

local mat = multmat(matx,maty) --multiply our matrixies
mat = multmat(mat,matz) --to get total matrix

norm = matxvec(mat,norm) --apply the matrix

return norm
end


rotpoint = function(norm,angs,axis) --point rotation
local mat = {1,0,0,0,1,0,0,0,1} --create 3x3 matrix arrays for xyz and fill it in with an identity matrix

local c = math.cos(angs)
local s = math.sin(angs)
local t = 1 - math.cos(angs)

mat[1] = t * axis[1]^2 + c
mat[2] = t * axis[1] * axis[2] + s * axis[3]
mat[3] = t * axis[1] * axis[3] - s * axis[2]

mat[4] = t * axis[1] * axis[2] - s * axis[3]
mat[5] = t * axis[2]^2 + c
mat[6] = t * axis[2] * axis[3] + s * axis[1]

mat[7] = t * axis[1] * axis[3] + s * axis[2]
mat[8] = t * axis[2] * axis[3] - s * axis[1]
mat[9] = t * axis[3]^2 + c

norm = matxvec(mat,norm) --apply the matrix

return norm
end

---------------------------------------------
-----end maths-----start transformations-----
---------------------------------------------


transmodel = function(m, t)
for i=1, #m do
local pnt = m[i]

pnt[1] = pnt[1] + (t[1] or t.x)
pnt[2] = pnt[2] + (t[2] or t.y)
pnt[3] = pnt[3] + (t[3] or t.z)

m[i] = pnt
end

return m
end


rotmodel = function(m, r)
local posx = m[1][1]
local posy = m[1][2]
local posz = m[1][3]

m = transmodel(m, {-posx,-posy,-posz})

for i=1, #m do
if r[3] ~= 0 then m[i] = rotpoint(m[i], r[3], m[2]) end
if r[2] ~= 0 then m[i] = rotpoint(m[i], r[2], m[3]) end
if r[1] ~= 0 then m[i] = rotpoint(m[i], r[1], m[4]) end
end

m = transmodel(m, {posx,posy,posz} )

return m
end


project = function(vec)
local X = cx + ( ((vec[1] or vec.x) / (vec[3] or vec.z)) * cx )
local Y = cy + (-((vec[2] or vec.y) / (vec[3] or vec.z)) * cy  * (w/h) )

return X,Y
end


--------------------------------------------------
-----end transformations-----start rendering------
--------------------------------------------------


drawline = function(v1, v2)
SDL.SDL_LockSurface(screen)

local xd = v1.x - v2.x
local yd = v1.y - v2.y

xd = xd/200
yd = yd/200

SDL.SDL_LockSurface(screen)

for i=1, 200, 1 do

local x,y = v1.x - i*xd,v1.y - i*yd

if x > 0 and y > 0 and x < w and y < h then
SDL.SDL_PutPixel(screen, x,y , blue)
end
end

SDL.SDL_UnlockSurface(screen)
end


drawmodel = function(m)
for i=6, #m - 1, 1 do
drawline( vec_2d( project( m[i] ) ),vec_2d( project( m[i+1] ) ) )
end
end


----------------------------------------------------------
-----start rendering-----start declarations and calls-----
----------------------------------------------------------


model = { {0,0,0},{0,0,1},{0,1,0},{1,0,0},{0,0,5000}, ---heh cobra mk3, format is position, fvec, uvec, svec, model

{0, 15, 0}, --index 5
{0, 15, -32.5},
{44, 10, -32.5},
{65, -3, -32.5},
{60, -3, -13}, --use 9 for gun 1

{16, -0.5, 32.5}, --index 10
{-16, -0.5, 32.5},
{-60, -3, -13}, --and 12 for gun 2
{-65, -3, -32.5},
{-44, 10, -32.5},

{0, 15, 0},
{44, 10, -32.5},
{60, -3, -13},
{16, -0.5, 32.5},
{0, 15, 0},

{-16, -0.5, 32.5},
{-60, -3, -13},
{-44, 10, -32.5},
{0, 15, -32.5},
{16, -15, -32.5},

{-16, -15, -32.5},
{-60, -3, -13},
{-65, -3, -32.5},
{-44, 10, -32.5},
{0, 15, -32.5},

{-16, -15, -32.5},
{-65, -3, -32.5},
{-16, -15, -32.5},
{-16, -0.5, 32.5},
{16, -0.5, 32.5},

{16, -15, -32.5},
{65, -3, -32.5},
{60, -3, -13},
{16, -15, -32.5}
}

model = transmodel(model, {0,0,200} )

vel = {0,0,0}
rot = {0,0,0}
drift = vec_3d(0,0,0)
shot = 0

-------------------------
-----start main loop-----
-------------------------

repeat
local event = SDL.SDL_Event_local()
SDL.SDL_PollEvent(event)
local key = event.key.keysym.sym

if event.type == SDL.SDL_KEYDOWN then
if key == SDL.SDLK_KP_MINUS then joyon = true end
if key == SDL.SDLK_SPACE then fire = 1 end
if key == SDL.SDLK_KP_PERIOD then kill = true end
if key == SDL.SDLK_KP8 then rot[1] = -0.01 end
if key == SDL.SDLK_KP2 then rot[1] = 0.01 end
if key == SDL.SDLK_KP4  then rot[2] = 0.01 end
if key == SDL.SDLK_KP6 then rot[2] = -0.01 end
if key == SDL.SDLK_KP7 then rot[3] = -0.01 end
if key == SDL.SDLK_KP9 then rot[3] = 0.01 end
if key == SDL.SDLK_KP1 then vel[1] = -0.001 end
if key == SDL.SDLK_KP3 then vel[1] = 0.001 end
if key == SDL.SDLK_KP_PLUS then vel[2] = 0.001 end
if key == SDL.SDLK_KP_ENTER then vel[2] = -0.001 end
if key == SDL.SDLK_KP5 then vel[3] = 0.005 end
if key == SDL.SDLK_KP0 then vel[3] = -0.001 end
elseif event.type == SDL.SDL_KEYUP then
if key == SDL.SDLK_SPACE then fire = 0 end
if key == SDL.SDLK_KP8 or key == SDL.SDLK_KP2 then rot[1] = 0 end
if key == SDL.SDLK_KP4 or key == SDL.SDLK_KP6 then rot[2] = 0 end
if key == SDL.SDLK_KP7 or key == SDL.SDLK_KP9 then rot[3] = 0 end
if key == SDL.SDLK_KP1 or key == SDL.SDLK_KP3 then vel[1] = 0 end
if key == SDL.SDLK_KP_PLUS or key == SDL.SDLK_KP_ENTER then vel[2] = 0 end
if key == SDL.SDLK_KP0 or key == SDL.SDLK_KP5 then vel[3] = 0 end
end

if SDL.SDL_NumJoysticks() and joyon then
stick = SDL.SDL_JoystickOpen(0)
axes = SDL.SDL_JoystickNumAxes(stick)
balls = SDL.SDL_JoystickNumHats(stick)
print(balls)

axisx = SDL.SDL_JoystickGetAxis(stick, 0)
axisy = SDL.SDL_JoystickGetAxis(stick, 1)
axisz = SDL.SDL_JoystickGetAxis(stick, 2)
axisx2 = SDL.SDL_JoystickGetAxis(stick, 3)
axisy2 = SDL.SDL_JoystickGetAxis(stick, 4)
axisz2 = SDL.SDL_JoystickGetAxis(stick, 5)

axisx  = axisx / 32768 --get sdl axes down to a -1 to 1 scale
axisy  = axisy / 32768
axisz  = -axisz / 32768
axisx2 = -axisx2 / 32768
axisy2 = axisy2 / 32768
axisz2 = axisz2 / 32768

if axes > 4 then vel[1] = axisy2 / 1000 end --check to make sure the axis exists before using it if no axis exists then use keyboard
if axes > 5 then vel[2] = axisz2 / 1000 end
if axes > 2 then vel[3] = (axisz + 0.333) / 333 end --throttle axis has 5x more forward than backward thrust
if axes > 1 then rot[1] = axisy / 100 end
if axes > 3 then rot[2] = axisx2 / 100 end
if axes > 0 then rot[3] = axisx / 100 end

fire = SDL.SDL_JoystickGetButton(stick, 0)

if SDL.SDL_JoystickGetButton(stick, 1) == 1 then --button 2 closes the stick and goes back to kb mode till kp- is hit again
joyon = false
SDL.SDL_JoystickClose(stick)
end
end

SDL.SDL_FillRect(screen, rect, grey)

muc = vec_3d( model[1] )
muf = vec_3d( model[2] )
muu = vec_3d( model[3] )
mus = vec_3d( model[4] )

meow = ( (mus - muc) * vel[1] )+( (muu - muc) * vel[2] )+( (muf - muc) * vel[3] )

drift = drift + meow

model = transmodel(model, drift)
model = rotmodel(model, rot)
drawmodel(model)

if fire == 1 then
shot = math.random(-5,5)
if shot > 0 then drawline(vec_2d(project(model[10])),vec_2d(project(model[5]))) end
if shot < 0 then drawline(vec_2d(project(model[13])),vec_2d(project(model[5]))) end
end

SDL.SDL_UpdateRect(screen, 0, 0, 0, 0)
until kill ~= nil


btw controls are

kp7,9 or joy x - roll
kp8,2 or joy y = pitch
kp5,0 or joy z = throttle
kp4,6 or joy twist = yaw
kp1,3 or joy axis 5 = lateral thrust
kp+,enter or joy axis 6 = verticle thrust
space or joy button 1 = fire laser

kp- enable joystick
joy button 2 stop using stick

kpdel end program

kp- turns on joystick

axes override keys if they exist.