- Having 2 image formats is needlessly complex
- Software blitting sucks (esp. alpha blending from a 8888 to a 1555 image)
Oh, and here's a (not very impressive) screenshot:
Moderators: Shine, Insert_witty_name
One of the first versions of Lua Player used the 8888 and it was too slow, this was the reason why I switched to the 1555 format. My future plans are to integrate pspgl for OpenGL support, which provides all graphics formats, but currently pspgl freezes sometimes on PSP 1.0 firmware versions, so until this bug is found, it might freeze on 1.5 as well, so needs some more time. But you can help to find the bug, if you have a 1.0 firmware PSP, see http://forums.ps2dev.org/viewtopic.php?t=3399Durante wrote:So, I now believe that switching to a single image format (with n bits alpha) as the standard in luaplayer and rendering everything hardware accelerated via gu is the way to go.
Yes, software blitting is really slow with 8888, especially alpha blending.Shine wrote:One of the first versions of Lua Player used the 8888 and it was too slow, this was the reason why I switched to the 1555 format.
Hmm, do you also plan to run the currently available 2D operations via OpenGL? Is there any particular reason why you want to use pspGL and not gu?Shine wrote:My future plans are to integrate pspgl for OpenGL support, which provides all graphics formats, ...
Yes, I want to do all 2D operations with OpenGL. pspgl itself sends the commands to the GE, like the pspgu lib does, so this should be the same speed (and this is the reason why it pspgl and pspgu can't be mixed), but pspgl has the advantage of providing (parts of) the OpenGL standard, which is well known and easy to use.Durante wrote:Hmm, do you also plan to run the currently available 2D operations via OpenGL? Is there any particular reason why you want to use pspGL and not gu?
That's fine, because this is missing from my pspgl integration. Perhaps you can merge it with my current version? I've already implemented some Lua mappings for OpenGL, but the image blitting uses C loops. Merged with your version we'll have OpenGL bindings and image blitting, all hardware accelerated :-)Durante wrote:Anyway, I now have an pspGL based LuaPlayer version that can blit images to the screen. Woohoo.
Code: Select all
System.usbDiskModeActivate()
glViewport(0, 0, 480, 272)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspectivef(75, 16/9, 0.5, 1000)
glMatrixMode(GL_MODELVIEW)
glShadeModel(GL_SMOOTH)
glColor3f(0, 0, 1)
angle = 0
pi = math.atan(1) * 4
detail = 10
values = {}
for x = 1, detail do
fx = x / detail
values[x] = {}
for y = 1, detail do
fy = y / detail
values[x][y] = math.sin(pi * fx) * math.sin(pi * fy) * math.sin(pi * fx * 3.1) * math.cos(pi * fy * 5) / 2
end
end
function getNormal(p0x, p0y, p0z, p1x, p1y, p1z, p2x, p2y, p2z)
v1x = p1x - p0x
v1y = p1y - p0y
v1z = p1z - p0z
v2x = p2x - p0x
v2y = p2y - p0y
v2z = p2z - p0z
-- cross product
nx = v1y*v2z - v1z*v2y
ny = v1z*v2x - v1x*v2z
nz = v1x*v2y - v1y*v2x
-- normalize
l = math.sqrt(nx*nx + ny*ny + nz*nz)
return nx / l, ny / l, nz / l
end
while true do
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
gluLookAt(0, 0, 2.5, 0, 0, 0, 0, 1, 0)
glRotatef(angle, 0, 0, 1)
glRotatef(angle, 0, 1, 0)
glRotatef(angle, 1, 0, 0)
angle = angle + 1
glBegin(GL_TRIANGLES)
mx = 3 / detail
my = 3 / detail
ofsx = -1
ofsy = -1
for x = 1, detail - 1 do
for y = 1, detail - 1 do
x0 = x * mx + ofsx
y0 = y * my + ofsy
z0 = values[x][y]
x1 = x0 + mx
y1 = y0
z1 = values[x + 1][y]
x2 = x1
y2 = y1 + my
z2 = values[x + 1][y + 1]
x3 = x0
y3 = y0 + my
z3 = values[x][y + 1]
nx, ny, nz = getNormal(x0, y0, z0, x1, y1, z1, x2, y2, z2)
glNormal3f(nx, ny, nz)
glColor3f(1, 0, 0)
glVertex3f(x0, y0, z0)
glVertex3f(x1, y1, z1)
glVertex3f(x2, y2, z2)
nx, ny, nz = getNormal(x0, y0, z0, x2, y2, z2, x3, y3, z3)
glNormal3f(nx, ny, nz)
glColor3f(0, 1, 0)
glVertex3f(x0, y0, z0)
glVertex3f(x2, y2, z2)
glVertex3f(x3, y3, z3)
end
end
glEnd()
glFlush()
screen.waitVblankStart()
screen.flip()
if Controls.read():start() then break end
end
Code: Select all
void initGraphics()
{
EGLConfig config;
EGLint num_configs;
EGLCHK(g_egl_dpy = eglGetDisplay(0));
EGLCHK(eglInitialize(g_egl_dpy, NULL, NULL));
EGLCHK(eglChooseConfig(g_egl_dpy, attrib_list, &config, 1, &num_configs));
EGLCHK(g_egl_ctx = eglCreateContext(g_egl_dpy, config, NULL, NULL));
EGLCHK(g_egl_surface = eglCreateWindowSurface(g_egl_dpy, config, 0, NULL));
EGLCHK(eglMakeCurrent(g_egl_dpy, g_egl_surface, g_egl_surface, g_egl_ctx));
glDisable(GL_STENCIL_TEST);
glDisable(GL_ALPHA_TEST);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_DEPTH_TEST);
glFrontFace(GL_CW);
glShadeModel(GL_SMOOTH);
glDisable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
glDepthRangef(0.0f, 1.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
initialized = 1;
}
Code: Select all
void disableGraphics()
{
eglTerminate(g_egl_dpy);
initialized = 0;
}
Code: Select all
void blitImageToScreen(int sx, int sy, int width, int height, Image* source, int dx, int dy)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
source->textureWidth, source->textureHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE/*_SHORT_1_5_5_5_REV*/, source->data);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f, 0.0f); // A
glVertex2i(dx, dy);
glTexCoord2f(1.0f, 0.0f); // B
glVertex2i(dx+source->imageWidth, dy);
glTexCoord2f(0.0f, 1.0f); // C
glVertex2i(dx, dy+source->imageHeight);
glTexCoord2f(1.0f, 1.0f); // D
glVertex2i(dx+source->imageWidth, dy+source->imageHeight);
glEnd();
}
void blitAlphaImageToScreen(int sx, int sy, int width, int height, Image* source, int dx, int dy)
{
blitImageToScreen(sx, sy, width, height, source, dx, dy);
}
Code: Select all
void fillScreenRect(Color color, int dx, int dy, int width, int height)
{
glBegin(GL_TRIANGLE_STRIP);
gl_colorize(color);
glVertex2i(dx, dy);
glVertex2i(dx+width, dy);
glVertex2i(dx, dy+height);
glVertex2i(dx+width, dy+height);
glEnd();
}
void drawLineScreen(int x0, int y0, int x1, int y1, Color color)
{
if (!initialized) return;
glBegin(GL_LINES);
gl_colorize(color);
glVertex2i(x0, y0);
glVertex2i(x1, y1);
glEnd();
}
Code: Select all
const static float CCONV_FAC = 1.0f/255.0f;
#define R(color) ((color >> 24 & 0xFF) * CCONV_FAC)
#define G(color) ((color >> 16 & 0xFF) * CCONV_FAC)
#define B(color) ((color >> 8 & 0xFF) * CCONV_FAC)
#define A(color) ((color & 0xFF) * CCONV_FAC)
static inline void gl_colorize(color)
{
glColor4f(R(color), G(color), B(color), A(color));
}
Code: Select all
void clearScreen(Color color)
{
if (!initialized) return;
glClearColor(R(color), G(color), B(color), A(color));
glClear(GL_COLOR_BUFFER_BIT);
}
void flipScreen()
{
if (!initialized) return;
EGLCHK(eglSwapBuffers(g_egl_dpy, g_egl_surface));
}
Code: Select all
void blitImageToScreen(int sx, int sy, int width, int height, Image* source, int dx, int dy)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
source->textureWidth, source->textureHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, source->data);
float wfac = 1.0f/source->textureWidth, hfac = 1.0f/source->textureHeight;
float tx0 = sx*wfac, ty0 = sy*hfac,
tx1 = tx0+width*wfac,
ty1 = ty0+height*hfac;
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(tx0, ty0); // A
glVertex2i(dx, dy);
glTexCoord2f(tx1, ty0); // B
glVertex2i(dx+width, dy);
glTexCoord2f(tx0, ty1); // C
glVertex2i(dx, dy+height);
glTexCoord2f(tx1, ty1); // D
glVertex2i(dx+width, dy+height);
glEnd();
}
Code: Select all
System.currentDirectory("System")
logfile = io.open("log.txt" , "w+")
logfile:write("TSR\n")
img = Image.load("test.png")
logfile:write("IL\n")
screen:blit(0, 0, img)
screen:blit(128, 0, img, 16, 16, 32, 32)
logfile:write("BL\n")
screen:fillRect(128, 128, 128, 128, Color.new(100, 50, 50))
for pos=0,255 do
screen:drawLine(480-255+pos, pos, 480, 0, Color.new(pos, 255-pos, 0))
end
logfile:write("RL\n")
screen.flip()
logfile:write("FL\n")
while not Controls.read():cross() do end
logfile:write("CR\n")
logfile:close()
Code: Select all
static inline void gl_colorize(color)
{
glColor4ubv(&color);
}
Are you going to make your gl version open to public?Durante wrote:Just noticed that I can implement the colors far more elegantly:Progress:Code: Select all
static inline void gl_colorize(color) { glColor4ubv(&color); }
My version now runs all the included programs perfectly, if a bit slower for some (due to the change to 32 bit). It will in turn be much faster for programs written to take advantage of HW acceleration that just blit everything to the screen in the game loop. All operations that render to the screen are hardware accelerated and support full alpha blending. Now I can finally start working on some app code!
Sure! Do you want it? ;)Zenurb wrote:Are you going to make your gl version open to public?
Code: Select all
INCDIR = /home/Peter/PSP/goop-pspgl/
CFLAGS = -G0 -Wall -O2 -fno-strict-aliasing
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
LIBDIR = /home/Peter/PSP/goop-pspgl/
LDFLAGS =
LIBS= -lGL -lGLU -llua -llualib -lpng -lz -lm -lmikmod -lmmio -lpspaudiolib -lpspaudio -lpspusb -lpspusbstor -lpsppower -lpspdebug -lpsphprm_driver -lpsputility -lpsprtc
I hope I can use sceGeSaveContext and sceGeRestoreContext for this to maintain two completly independent states and switch it on the first call of each domain.Durante wrote:In case you want to use 3d stuff and 2d functions at the same time you'd need to extract the glMatrixMode... paragraph (last before initialized=1;) and execute it at the start of each 2D function.
32 bit only, mostly for simplicity. If you want to integrate it, get the zip I linked to above, it is a bit more current than the code I posted in this thread.Shine wrote:Thanks for your implementations. Do you have changed the image structure to 32 bit, only?
That's an exceedingly great and very useful thing to have, and also something that I'd never have the staying power to finish for a hobbyist project ;). Keep up the great work!Shine wrote:Currently I'm writing some regressions tests, which counts the time for each graphics operation, draws test images in memory and on screen, saves it and compares the md5 sum for each saved PNG and the time which was needed to render it. Then I'll include pspgl and I'll see what breaks :-)
Code: Select all
nil screen.blitScaled(x, y, Image source, scalex, scaley, [sourcex, sourcey, width, height])
nil screen.blitRotated(x, y, Image source, angle, [sourcex, sourcey, width, height])
nil screen.blitRotScale(x, y, Image source, angle, scalex, scaley, [sourcex, sourcey, width, height])
Code: Select all
img = Image.load("test.png")
buff = Image.createEmpty(128, 64)
buff:blit(0, 0, img)
buff:blit(64, 0, img)
screen:clear(Color.new(0,128,128))
screen:blit(0, 0, img)
screen:blit(128, 0, img, 16, 16, 32, 32)
screen.blitScaled(200, 0, img, 0.5, 2.5)
screen.blitRotated(170, 150, img, 33.3)
screen.blitRotScale(320, 150, img, 45.0, 0.7, 1.4);
screen:blit(0, 90, buff)
screen:fillRect(0, 180, 32, 32, Color.new(255, 0, 0))
screen:fillRect(32, 180, 32, 32, Color.new(0, 255, 0))
screen:fillRect(0, 212, 32, 32, Color.new(0, 0, 255))
for pos=0,255 do
screen:drawLine(480-255+pos, pos, 480, 0, Color.new(pos, 255-pos, 0))
end
screen.flip()
screen:save("shot.png")
while not Controls.read():start() do end
I don't even like it myself! Your proposal is indeed much better. The blit functions have enough arguments as is ;)nevyn wrote:I don't like your API
Code: Select all
unsigned r = CLAMP(luaL_checkint(L, 1), 0, 255);
unsigned g = CLAMP(luaL_checkint(L, 2), 0, 255);
unsigned b = CLAMP(luaL_checkint(L, 3), 0, 255);
unsigned a;
if (argc == 4) {
a = CLAMP(luaL_checkint(L, 3), 0, 255); // EVIL
} else {
a = 255;
}
Haha. Sorry about that... Looks like code I've been responsible for.Durante wrote:I don't even like it myself! Your proposal is indeed much better. The blit functions have enough arguments as is ;)nevyn wrote:I don't like your API
However, it would be kind of strange to have a rotation / scale factors "in the image" and then only have them work when blitting to the screen. What are your thoughts on that?
This kind of stateful blitting information is also what I planned for the next feature enbled by OpenGL that I'll implement, image tinting. I need that for my game as well ;)
Btw, I found a kind of evil bug that is not from me for a change! In luagraphics.c, static int Color_new (lua_State *L):Took me some time to figure THAT out. Copy & paste's a bitch.Code: Select all
unsigned r = CLAMP(luaL_checkint(L, 1), 0, 255); unsigned g = CLAMP(luaL_checkint(L, 2), 0, 255); unsigned b = CLAMP(luaL_checkint(L, 3), 0, 255); unsigned a; if (argc == 4) { a = CLAMP(luaL_checkint(L, 3), 0, 255); // EVIL } else { a = 255; }
I think this is a good idea, because Lua Player is all about simplicity, so now we have only true color again instead of letting the user decide which pixelformat to use, with makes it simpler. This means we have to implement some caching for the images in VRAM for better speed and perhaps texture swizzling.Durante wrote:32 bit only, mostly for simplicity.
Code: Select all
red = Color.new(255, 0, 0)
green = Color.new(0, 255, 0)
blue = Color.new(0, 0, 255)
black = Color.new(0, 0, 0)
white = Color.new(255, 255, 255)
cyan = Color.new(100, 255, 255)
val = 0
logo = Image.createEmpty(64, 64)
logo:print(20, 20, "Lua", white)
logo:print(10, 40, "Player", white)
vertices = {
{u=0, v=0, color=red, x=-1, y=-1, z= 1}, -- 0
{u=1, v=0, color=red, x=-1, y= 1, z= 1}, -- 4
{u=1, v=1, color=red, x= 1, y= 1, z= 1}, -- 5
{u=0, v=0, color=red, x=-1, y=-1, z= 1}, -- 0
{u=1, v=1, color=red, x= 1, y= 1, z= 1}, -- 5
{u=0, v=1, color=red, x= 1, y=-1, z= 1}, -- 1
{u=0, v=0, color=red, x=-1, y=-1, z=-1}, -- 3
{u=1, v=0, color=red, x= 1, y=-1, z=-1}, -- 2
{u=1, v=1, color=red, x= 1, y= 1, z=-1}, -- 6
{u=0, v=0, color=red, x=-1, y=-1, z=-1}, -- 3
{u=1, v=1, color=red, x= 1, y= 1, z=-1}, -- 6
{u=0, v=1, color=red, x=-1, y= 1, z=-1}, -- 7
{u=0, v=0, color=green, x= 1, y=-1, z=-1}, -- 0
{u=1, v=0, color=green, x= 1, y=-1, z= 1}, -- 3
{u=1, v=1, color=green, x= 1, y= 1, z= 1}, -- 7
{u=0, v=0, color=green, x= 1, y=-1, z=-1}, -- 0
{u=1, v=1, color=green, x= 1, y= 1, z= 1}, -- 7
{u=0, v=1, color=green, x= 1, y= 1, z=-1}, -- 4
{u=0, v=0, color=green, x=-1, y=-1, z=-1}, -- 0
{u=1, v=0, color=green, x=-1, y= 1, z=-1}, -- 3
{u=1, v=1, color=green, x=-1, y= 1, z= 1}, -- 7
{u=0, v=0, color=green, x=-1, y=-1, z=-1}, -- 0
{u=1, v=1, color=green, x=-1, y= 1, z= 1}, -- 7
{u=0, v=1, color=green, x=-1, y=-1, z= 1}, -- 4
{u=0, v=0, color=blue, x=-1, y= 1, z=-1}, -- 0
{u=1, v=0, color=blue, x= 1, y= 1, z=-1}, -- 1
{u=1, v=1, color=blue, x= 1, y= 1, z= 1}, -- 2
{u=0, v=0, color=blue, x=-1, y= 1, z=-1}, -- 0
{u=1, v=1, color=blue, x= 1, y= 1, z= 1}, -- 2
{u=0, v=1, color=blue, x=-1, y= 1, z= 1}, -- 3
{u=0, v=0, color=blue, x=-1, y=-1, z=-1}, -- 4
{u=1, v=0, color=blue, x=-1, y=-1, z= 1}, -- 7
{u=1, v=1, color=blue, x= 1, y=-1, z= 1}, -- 6
{u=0, v=0, color=blue, x=-1, y=-1, z=-1}, -- 4
{u=1, v=1, color=blue, x= 1, y=-1, z= 1}, -- 6
{u=0, v=1, color=blue, x= 1, y=-1, z=-1}, -- 5
}
while true do
sceGuStart()
-- clear screen
sceGuClearColor(cyan)
sceGuClearDepth(0);
sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT)
-- setup matrices for cube
sceGumMatrixMode(GU_PROJECTION)
sceGumLoadIdentity()
sceGumPerspective(75, 16/9, 0.5, 1000)
sceGumMatrixMode(GU_VIEW)
sceGumLoadIdentity()
sceGumMatrixMode(GU_MODEL)
sceGumLoadIdentity()
sceGumTranslate(0, 0, -3.5);
sceGumRotateXYZ(val * 0.79 * (GU_PI/180), val * 0.98 * (GU_PI/180.0), val * 1.32 * (GU_PI/180.0))
-- setup texture
sceGuTexImage(logo)
sceGuTexFunc(GU_TFX_ADD, GU_TCC_RGB)
sceGuTexEnvColor(Color.new(0xff, 0xff, 0xff))
sceGuTexFilter(GU_LINEAR, GU_LINEAR)
sceGuTexScale(1, 1)
sceGuTexOffset(0, 0)
sceGuAmbientColor(white)
-- draw cube
sceGumDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF|GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_3D, vertices)
sceGuFinish()
sceGuSync(0, 0)
val = val + 1
if Controls.read():start() then break end
screen.waitVblankStart()
screen.flip()
end
We need the list all the time, this is the reason I have initialized it as a static variable. It could be initialized on heap with memalign, but it's all in the same RAM, which means it has no advantage (I think).sweetlilmre wrote:Updating via SVN fixes the issue (updating mikmod that is). If anyone knows the reason why this occurs, I'd love an explanation.
Also, would it not be a better idea to create the list on the heap? (I assume alignment issue may prevent this?)
Do you have an idea how to enhance the 3D API of the new Lua Player 0.12? Currently it is nearly a copy of the sceGu functions, see http://wiki.ps2dev.org/psp:lua_player:f ... gu_mapping . I think this is ok for the simple functions, like sceGuEnable. But the sceGumDrawArray looks a bit too low-level and not very intuitive. You have to specify some binary flags and then you have to provide a table with the right order of the vertex components. Perhaps it would be better to write some object oriented interface for vertex arrays (which should also support "weights" and multiple vertices per vertex element, which are used for the PSP skin and morphing features) or at least to use named vertex components? But then perhaps the low-level C-vertex array should be cached for better performance.nevyn wrote:I don't like your API, but then again, that's why I'm the API guy ;)
Code: Select all
mything = Mesh:new("mything.obj")
node = Scene.addNode(1, 1, 1) -- x, y, z pos
node:rotate(0, 1, 0, 45) -- axis, angle
node:scale(2, 1, 1) -- xyz scale factor
subnode = node:addNode() -- 0,0,0
mything:attach(subnode)
Scene.render()
Mmm, that's the kind of level I like it on :)Durante wrote:I believe that you/we/Luaplayer should go even higher level, providing the end-user with something akin to (ideally):Doing it on that level also does the dirty work in C, allowing much faster execution. The only downside is that it's a lot of work ;)Code: Select all
mything = Mesh:new("mything.obj") node = Scene.addNode(1, 1, 1) -- x, y, z pos node:rotate(0, 1, 0, 45) -- axis, angle node:scale(2, 1, 1) -- xyz scale factor subnode = node:addNode() -- 0,0,0 mything:attach(subnode) Scene.render()
An IMHO very well designed but VERY extensive 3d engine:
http://ogre3d.org/
At least part of the API would be great to steal ;)
I'd like to get to the bottom of that problem. I think we left it at me asking you for some more detailed dumps of what happens around the lockup. http://forums.ps2dev.org/viewtopic.php?p=26557#26557Shine wrote:Another problem are the pspgl implementations. The goop pspgl lib still freezes on my 1.00 PSP
Sure you do. I worked out how the curved surface stuff worked and put it into PSPGL as extensions; chip picked up my work and added it into GU. PSPGL also implements skinning (vertex blending), but I haven't done mesh morphing yet.But the main reason for me to use the sceGu* and sceGum* functions is that we don't have all the nice PSP functions with pspgl, like spline surfaces, beziers, skin morphing etc.