ps2 and lua
ps2 and lua
I noticed that psp and lua seems to be growing and that lua for psp, or luaplayer makes it easy to do homebrew games. Is there anything similar lua wise for ps2?
Re: ps2 and lua
You can download the source from http://www.lua.org It is standard C, so it should compile with every C compiler. You could take a look how to build the static libraries in the PSP repository (note: the Lua version in the PSP repository is slightly patched for using floats instead of doubles as the Lua "number" type): http://svn.ps2dev.org/listing.php?repna ... rev=0&sc=0
I'm using Lua for development on the PS2 and it is beginning to actually work. I'm not familiar with LuaPlayer, but it should be relatively straightforward to create some kind of Lua-based SDK for the PS2 development (I'm not sure how advanced/mature LuaPlayer is).
It is very easy to expose C functions to Lua. The only difficult part is to map the data structures between the two languages. I have some simple rendering and pad input working, but that is it so far. I'd be happy to post any development if others are interested.
The nice thing about using Lua is that if the Lua SDK is complete enough, then the programmer doesn't have to mess with compiling any C code at all (and the difficulties with cygwin or trying to setup a linux dev box). It is easy to redistribute the .elf binary and then just develop using Lua. However, that would require a lot more sophistication for the SDK.
It is very easy to expose C functions to Lua. The only difficult part is to map the data structures between the two languages. I have some simple rendering and pad input working, but that is it so far. I'd be happy to post any development if others are interested.
The nice thing about using Lua is that if the Lua SDK is complete enough, then the programmer doesn't have to mess with compiling any C code at all (and the difficulties with cygwin or trying to setup a linux dev box). It is easy to redistribute the .elf binary and then just develop using Lua. However, that would require a lot more sophistication for the SDK.
I am doing my own port. I didn't know there was any work completed already.
This work is under pretty heavy revision still, and at the moment I'm not really trying to build a "re-useable engine" but just trying to work on my little game.
But, I haven't done anything in the code that is highly custom yet. Most of the engine is actually implemented in Lua at the moment. I'm not sure where to post/host this stuff if you want to look at it. What is convenient for you?
This work is under pretty heavy revision still, and at the moment I'm not really trying to build a "re-useable engine" but just trying to work on my little game.
But, I haven't done anything in the code that is highly custom yet. Most of the engine is actually implemented in Lua at the moment. I'm not sure where to post/host this stuff if you want to look at it. What is convenient for you?
First, I got Lua compiling. I switched the datatype to float instead of double and switched the math.* functions to floating point (ie: math.sin calls sinf() instead of sin()).
Then I just began implementing C functions in Lua that allow basic interaction and mapping between the PS2 and Lua. The main.elf loads a file called main.lua and then just sits in a loop executing the "update" global function that is defined by main.lua. That function basically controls all rendering and pad input, etc.
As far as rendering goes, you can implement some buffers to render or use the "immediate mode" calls like in OpenGL. Obviously, the buffers are faster but a little harder to use.
Buffer example:
Immediate Mode example:
Obviously, some of this code is silly to write in Lua, but it's quick and easy to write and I'll move it to C for speed later.
All the calls that begin with "lp2" are written in the engine in C. The other calls are implemented as Lua functions elsewhere.
Both rendering modes honor the current MODELVIEW and PROJECTION matrices and you can call lp2PushMatrix() lp2PopMatrix(), lp2Translate(), lp2Rotate(), and lp2MultMatrix().
It isn't too fast and it doesn't support texturing or lighting yet.
Oh, and it also runs in OpenGL on the PC for prototyping.
Then I just began implementing C functions in Lua that allow basic interaction and mapping between the PS2 and Lua. The main.elf loads a file called main.lua and then just sits in a loop executing the "update" global function that is defined by main.lua. That function basically controls all rendering and pad input, etc.
Code: Select all
function setupFullPerspective(aspect)
lp2MatrixMode(LP2.PROJECTION)
lp2LoadIdentity()
lp2Perspective(math.pi/4, aspect, 2, 2000)
lp2MatrixMode(LP2.MODELVIEW)
lp2LoadIdentity()
end
function updateObj(obj, pad, millis)
local offX = normJoyAxis(pad.LJOY_H) * millis/16
local newX = obj.pos[0] + offX
local offY = -normJoyAxis(pad.LJOY_V) * millis/16
local newY = obj.pos[1] + offY
............
end
function update(millis)
lp2BeginScene(0,0,0)
setupFullPerspective(screenAspect)
lp2ReadInput()
for i=1,pads do
updateObj(obj[i], pad[i], millis)
end
lp2LoadIdentity()
cameraTx(camPos, camRot)
lp2PushMatrix()
localWorldTx(obj[1])
startTimeBlock("drawing chars 1 and 2")
if (normJoyAxis(pad[1].LJOY_H) ~= 0) or (normJoyAxis(pad[1].LJOY_V) ~= 0) then
char1.cycle = char1.cycle + 0.2 * millis/16
char1:moveForward(char1.cycle)
else
char1.cycle = 0
char1:toStandingPose()
end
char1:draw()
lp2PopMatrix()
--Above code repeats for all inputs--
-- render walls and floors
for i=1,#floors do
floors[i]:draw()
end
for i=1,#walls do
walls[i]:draw()
end
lp2WaitVSync()
lp2EndScene(0,0,0)
end
Buffer example:
Code: Select all
pointCount = 36
cubePoints = lp2CreatePointArray(pointCount)
cubePoints[0] = 0 cubePoints[1] = 2 cubePoints[2] = 1
cubePoints[3] = 1 cubePoints[4] = 2 cubePoints[5] = 3
cubePoints[6] = 4 cubePoints[7] = 5 cubePoints[8] = 6
cubePoints[9] = 5 cubePoints[10] = 7 cubePoints[11] = 6
cubePoints[12] = 8 cubePoints[13] = 9 cubePoints[14] = 10
cubePoints[15] = 9 cubePoints[16] = 11 cubePoints[17] = 10
cubePoints[18] = 12 cubePoints[19] = 14 cubePoints[20] = 13
cubePoints[21] = 13 cubePoints[22] = 14 cubePoints[23] = 15
cubePoints[24] = 16 cubePoints[25] = 18 cubePoints[26] = 17
cubePoints[27] = 17 cubePoints[28] = 18 cubePoints[29] = 19
cubePoints[30] = 20 cubePoints[31] = 21 cubePoints[32] = 22
cubePoints[33] = 21 cubePoints[34] = 23 cubePoints[35] = 22
vertexCount = 24
vertices = lp2CreateVertexArray(vertexCount)
vertices[0*4] = 6 vertices[0*4+1] = 10 vertices[0*4+2] = 10 vertices[0*4+3]=1
vertices[1*4] = 6 vertices[1*4+1] = 10 vertices[1*4+2] =-10 vertices[1*4+3]=1
vertices[2*4] = 10 vertices[2*4+1] =-10 vertices[2*4+2] = 10 vertices[2*4+3]=1
vertices[3*4] = 10 vertices[3*4+1] =-10 vertices[3*4+2] =-10 vertices[3*4+3]=1
vertices[4*4] =- 6 vertices[4*4+1] = 10 vertices[4*4+2] = 10 vertices[4*4+3]=1
vertices[5*4] =- 6 vertices[5*4+1] = 10 vertices[5*4+2] =-10 vertices[5*4+3]=1
vertices[6*4] =-10 vertices[6*4+1] =-10 vertices[6*4+2] = 10 vertices[6*4+3]=1
vertices[7*4] =-10 vertices[7*4+1] =-10 vertices[7*4+2] =-10 vertices[7*4+3]=1
vertices[8*4] =- 6 vertices[8*4+1] = 10 vertices[8*4+2] = 10 vertices[8*4+3]=1
vertices[9*4] = 6 vertices[9*4+1] = 10 vertices[9*4+2] = 10 vertices[9*4+3]=1
vertices[10*4]=- 6 vertices[10*4+1]= 10 vertices[10*4+2]=-10 vertices[10*4+3]=1
vertices[11*4]= 6 vertices[11*4+1]= 10 vertices[11*4+2]=-10 vertices[11*4+3]=1
vertices[12*4]=-10 vertices[12*4+1]=-10 vertices[12*4+2]= 10 vertices[12*4+3]=1
vertices[13*4]= 10 vertices[13*4+1]=-10 vertices[13*4+2]= 10 vertices[13*4+3]=1
vertices[14*4]=-10 vertices[14*4+1]=-10 vertices[14*4+2]=-10 vertices[14*4+3]=1
vertices[15*4]= 10 vertices[15*4+1]=-10 vertices[15*4+2]=-10 vertices[15*4+3]=1
vertices[16*4]=- 6 vertices[16*4+1]= 10 vertices[16*4+2]= 10 vertices[16*4+3]=1
vertices[17*4]= 6 vertices[17*4+1]= 10 vertices[17*4+2]= 10 vertices[17*4+3]=1
vertices[18*4]=-10 vertices[18*4+1]=-10 vertices[18*4+2]= 10 vertices[18*4+3]=1
vertices[19*4]= 10 vertices[19*4+1]=-10 vertices[19*4+2]= 10 vertices[19*4+3]=1
vertices[20*4]=- 6 vertices[20*4+1]= 10 vertices[20*4+2]=-10 vertices[20*4+3]=1
vertices[21*4]= 6 vertices[21*4+1]= 10 vertices[21*4+2]=-10 vertices[21*4+3]=1
vertices[22*4]=-10 vertices[22*4+1]=-10 vertices[22*4+2]=-10 vertices[22*4+3]=1
vertices[23*4]= 10 vertices[23*4+1]=-10 vertices[23*4+2]=-10 vertices[23*4+3]=1
colours = lp2CreateVertexArray(vertexCount)
for i = 0,vertexCount-1 do
if (i < 8) then
colours[i*4] = 1
else
colours[i*4] = 0
end
if (i >= 8 and i < 16) then
colours[i*4+1] = 1
else
colours[i*4+1] = 0
end
if (i >= 16) then
colours[i*4+2] = 1
else
colours[i*4+2] = 0
end
colours[i*4+3] = 1
end
lp2RenderBuffers(vertexCount, vertices, colours, pointCount, cubePoints)
Code: Select all
function drawCubeAt(x, y, z, width, height, depth, r, g, b, a)
r = r or 1
g = g or 1
b = b or 1
a = a or 1
x = x or 0
y = y or 0
z = z or 0
width = width or 1
height = height or 1
depth = depth or 1
lp2Begin(LP2.TRIANGLES)
lp2Color(r, g, b, a)
lp2Vertex(x, y + height, z + depth)
lp2Vertex(x, y, z + depth)
lp2Vertex(x + width, y, z + depth)
lp2Vertex(x + width, y, z + depth)
lp2Vertex(x + width, y + height, z + depth)
lp2Vertex(x, y + height, z + depth)
lp2Color(r+0.05, g+0.05, b+0.05, a)
lp2Vertex(x + width, y + height, z + depth)
lp2Vertex(x + width, y, z + depth)
lp2Vertex(x + width, y, z)
lp2Vertex(x + width, y, z)
lp2Vertex(x + width, y + height, z)
lp2Vertex(x + width, y + height, z + depth)
lp2Color(r+0.10, g+0.10, b+0.10, a)
lp2Vertex(x, y + height, z)
lp2Vertex(x + width, y, z)
lp2Vertex(x, y, z)
lp2Vertex(x + width, y, z)
lp2Vertex(x, y + height, z)
lp2Vertex(x + width, y + height, z)
lp2Color(r+0.15, g+0.15, b+0.15, a)
lp2Vertex(x, y + height, z + depth)
lp2Vertex(x, y, z)
lp2Vertex(x, y, z + depth)
lp2Vertex(x, y, z)
lp2Vertex(x, y + height, z + depth)
lp2Vertex(x, y + height, z)
lp2Color(r+0.20, g+0.20, b+0.20, a)
lp2Vertex(x, y + height, z + depth)
lp2Vertex(x + width, y + height, z)
lp2Vertex(x, y + height, z)
lp2Vertex(x, y + height, z + depth)
lp2Vertex(x + width, y + height, z + depth)
lp2Vertex(x + width, y + height, z)
lp2Color(r+0.25, g+0.25, b+0.25, a)
lp2Vertex(x, y, z + depth)
lp2Vertex(x, y, z)
lp2Vertex(x + width, y, z)
lp2Vertex(x, y, z + depth)
lp2Vertex(x + width, y, z)
lp2Vertex(x + width, y, z + depth)
lp2End()
end
All the calls that begin with "lp2" are written in the engine in C. The other calls are implemented as Lua functions elsewhere.
Both rendering modes honor the current MODELVIEW and PROJECTION matrices and you can call lp2PushMatrix() lp2PopMatrix(), lp2Translate(), lp2Rotate(), and lp2MultMatrix().
It isn't too fast and it doesn't support texturing or lighting yet.
Oh, and it also runs in OpenGL on the PC for prototyping.
sweeeeeet !
Only a binary version has been released with the patch file for the 5.0.2 sources, if you have the 5.1 patched sources, it's better of course :)
I tried yesterday nigth to compilate the 5.1 but just got a very bad exception and I didn't had the time to found out what was wrong before beeing tired and going to sleep :]
So if you already have the lua interpreter patched, up & running, it could be nice to put it under SVN (here at ps2dev) ?
Just ask oobles for an access, or send me it by email if you prefer and I'll upload it.
Regards.
Only a binary version has been released with the patch file for the 5.0.2 sources, if you have the 5.1 patched sources, it's better of course :)
I tried yesterday nigth to compilate the 5.1 but just got a very bad exception and I didn't had the time to found out what was wrong before beeing tired and going to sleep :]
So if you already have the lua interpreter patched, up & running, it could be nice to put it under SVN (here at ps2dev) ?
Just ask oobles for an access, or send me it by email if you prefer and I'll upload it.
Regards.
I guess I should just get SVN access at some point as I have run into a few things in the sources to ps2sdk already. How do I go about that? Do I have to pass a double-blind taste test? I haven't used SVN yet, but I've used cvs and perforce plenty.
My code is organized pretty hideously at the moment. I'm not used to straight-C development, have done mostly OO stuff for the past 10 years.
I fixed a few lingering problems last night so now the engine doesn't require 60fps and I fudged the projection matrix a little so the OpenGL and PS2 versions now look identical. I guess I should switch to gsKit instead of libdraw and libgraph, but I probably won't do that until I run into another blocking problem.
Actually, my current most annoying problem is that sometimes I get polygons shearing all over the screen as if the clipping/transform code isn't working right. It's not completely reliable, but it's really annoying.
My code is organized pretty hideously at the moment. I'm not used to straight-C development, have done mostly OO stuff for the past 10 years.
I fixed a few lingering problems last night so now the engine doesn't require 60fps and I fudged the projection matrix a little so the OpenGL and PS2 versions now look identical. I guess I should switch to gsKit instead of libdraw and libgraph, but I probably won't do that until I run into another blocking problem.
Actually, my current most annoying problem is that sometimes I get polygons shearing all over the screen as if the clipping/transform code isn't working right. It's not completely reliable, but it's really annoying.
Ah! Try adding a blank line at the top of the script.
I know that sounds dumb, but I had to modify all of my scripts to always begin with a single blank line and it fixed some strange problem that I never diagnosed.
I was guessing it has something to do with file io settings and maybe the line terminator being 13,10 or just 13 or whatever. I am also suspecting that this is related to the fact that I can't load precompiled lua scripts at runtime on the PS2 either.
Is there something you had to do that was different than the diff I sent you? That is strange...
I just looked at luaL_loadfile() (in lauxlib.c) and it inspects the first character by using getc() and then calls ungetc()... Does anyone know if ungetc() works? I'm a little suspicious of that...
I know that sounds dumb, but I had to modify all of my scripts to always begin with a single blank line and it fixed some strange problem that I never diagnosed.
I was guessing it has something to do with file io settings and maybe the line terminator being 13,10 or just 13 or whatever. I am also suspecting that this is related to the fact that I can't load precompiled lua scripts at runtime on the PS2 either.
Is there something you had to do that was different than the diff I sent you? That is strange...
I just looked at luaL_loadfile() (in lauxlib.c) and it inspects the first character by using getc() and then calls ungetc()... Does anyone know if ungetc() works? I'm a little suspicious of that...
Last edited by SSpeare on Wed Jun 14, 2006 3:15 am, edited 1 time in total.
ah, I sent it to someone else. I just sent it to you also at your gmail account. I just editted the above post with info about what might be causing the problem.
Using my Makefile might make a difference. It is just based on the makefiles from ps2sdk. It isn't the one that comes with Lua because the Lua version doesn't have a compatibility section for PS2. I guess I could have tried to figure out what that would look like, but I didn't! My Makefile will not specify LUA_USE_POPEN so that won't get compiled in.
Rather, it won't specify LUA_USE_POSIX which then won't specify LUA_USE_POPEN.
Using my Makefile might make a difference. It is just based on the makefiles from ps2sdk. It isn't the one that comes with Lua because the Lua version doesn't have a compatibility section for PS2. I guess I could have tried to figure out what that would look like, but I didn't! My Makefile will not specify LUA_USE_POPEN so that won't get compiled in.
Rather, it won't specify LUA_USE_POSIX which then won't specify LUA_USE_POPEN.
I've done the same thing but reusing the supplied makefile, just adding necessary stuff specific to the ps2. But on my side, I also made a stub file to add missing function like locale, etc... and kept the io library, so it should be theorically complete !
concerning my gmail account, did you sent it to [email protected] ?
concerning my gmail account, did you sent it to [email protected] ?
So i just got back at home and tested...
and.. It's working.. i will investigate on why that damn blank line is needed.
I ran severals lua scripts and all are working, so it's good :)
In the mean time, I propose you to add our port into svn, so you'll be able to add your changes if you see something else missing ?
do you agree ?
and.. It's working.. i will investigate on why that damn blank line is needed.
I ran severals lua scripts and all are working, so it's good :)
In the mean time, I propose you to add our port into svn, so you'll be able to add your changes if you see something else missing ?
do you agree ?
I agree. I'm just not sure exactly how best to put it into the SVN here on ps2dev.org. What should the folder be called? I have used perforce and CVS but not SVN and I don't want to mess anything up. I guess it should go under ps2/trunk, right? maybe:
ps2/trunk/lua
or something?
Also, I think I found the problem. ungetc() puts a character back in the putback buffer, but the putback buffer is not checked during fread() so it will be ignored at the next fread(). I believe that the lua will use the fread() call from: getF() in lauxlib.c because that is passed into lua_load which passes it on into the parser.
I think the fix would be to update fread() in stdio.c to something like (just off the top of my head):
ps2/trunk/lua
or something?
Also, I think I found the problem. ungetc() puts a character back in the putback buffer, but the putback buffer is not checked during fread() so it will be ignored at the next fread(). I believe that the lua will use the fread() call from: getF() in lauxlib.c because that is passed into lua_load which passes it on into the parser.
I think the fix would be to update fread() in stdio.c to something like (just off the top of my head):
Code: Select all
size_t fread(void *buf, size_t r, size_t n, FILE *stream)
{
size_t ret;
switch(stream->type) {
case STD_IOBUF_TYPE_NONE:
case STD_IOBUF_TYPE_GS:
case STD_IOBUF_TYPE_SIO:
case STD_IOBUF_TYPE_STDOUTHOST:
/* cannot read from stdout or stderr. */
ret = 0;
break;
default:
/* attempt to read from the stream file. */
if (stream->has_putback) {
stream->has_putback = 0;
buf[0] = stream->putback;
buf++;
/* subtract 1 from n to avoid buffer overflow and keep an even record count */
ret = (_ps2sdk_read(stream->fd, buf, (int)(r * (n-1))) / (int)r);
} else {
ret = (_ps2sdk_read(stream->fd, buf, (int)(r * n)) / (int)r);
}
}
return (ret);
}
Hi,
I just checked your code and just corrected one thing (1 should be substracted to r*n and not only n), but your correction seems correct to me, i'll test it tonight :)
giving :
I also checked in all others IO routines, and that flag is not checked (where it should be) in fwrite, ftell, fgetpos and not reseted in some others (like fsetpos, etc..)
dunno if we need them aswell for the moment, lua/ps2 need some more extensive testing :)
advice from the official libc maintainer ? (Pixel ??? still alive ?)
evilo.
I just checked your code and just corrected one thing (1 should be substracted to r*n and not only n), but your correction seems correct to me, i'll test it tonight :)
giving :
Code: Select all
size_t fread(void *buf, size_t r, size_t n, FILE *stream)
{
size_t ret;
switch(stream->type) {
case STD_IOBUF_TYPE_NONE:
case STD_IOBUF_TYPE_GS:
case STD_IOBUF_TYPE_SIO:
case STD_IOBUF_TYPE_STDOUTHOST:
/* cannot read from stdout or stderr. */
ret = 0;
break;
default:
/* attempt to read from the stream file. */
if (stream->has_putback) {
buf[0] = stream->putback;
buf++;
stream->has_putback = 0;
/* subtract 1 from r * n to avoid buffer overflow and keep an even record count */
ret = (_ps2sdk_read(stream->fd, buf, (int)((r * n) -1 ))) / (int)r);
} else {
ret = (_ps2sdk_read(stream->fd, buf, (int)(r * n)) / (int)r);
}
}
return (ret);
}
dunno if we need them aswell for the moment, lua/ps2 need some more extensive testing :)
advice from the official libc maintainer ? (Pixel ??? still alive ?)
evilo.
Ya. I wrote it that way at first and then changed it. But I think that way is better upon further reflection. I guess fread() will return partial records if your record size is >1. That seems odd to me, but that is the current behavior so I guess we should just leave it alone for the moment.
e.g.
If I ask to read 10 records of size 4, and fread() finds 38 bytes, I would expect it to return 9 records of size 4 (36 bytes), not 38 bytes which is 9 records plus a half record. The return value of fread() will be 9 because it is forced to an int, so it will lie about how much data it read. Then if you fread() again you will have mis-aligned data because you have already read 1/2 of the record, but you didn't know that because the function lied.
I'm not sure what the behavior of fread() is in a standard implementation, though... I haven't used C extensively in a long time. This may be just a caveat.
That being said, it should still probably subtract the 1 from (r * n)... Either way it won't fix the above problem.
EDIT: Moved fread() and ungetc() discussion to a new thread in ps2sdk
e.g.
If I ask to read 10 records of size 4, and fread() finds 38 bytes, I would expect it to return 9 records of size 4 (36 bytes), not 38 bytes which is 9 records plus a half record. The return value of fread() will be 9 because it is forced to an int, so it will lie about how much data it read. Then if you fread() again you will have mis-aligned data because you have already read 1/2 of the record, but you didn't know that because the function lied.
I'm not sure what the behavior of fread() is in a standard implementation, though... I haven't used C extensively in a long time. This may be just a caveat.
That being said, it should still probably subtract the 1 from (r * n)... Either way it won't fix the above problem.
EDIT: Moved fread() and ungetc() discussion to a new thread in ps2sdk