Alpha blending, hardware acceleration

Discuss using and improving Lua and the Lua Player specific to the PSP.

Moderators: Shine, Insert_witty_name

Durante
Posts: 65
Joined: Sun Oct 02, 2005 6:07 am
Location: Austria

Alpha blending, hardware acceleration

Post by Durante »

I implemented alpha blending for LuaPlayer by adding an additional class (ImageEx) for ABGR 8888 images. Everything works except that I can't get gu to blend my images directly to the screen. Anyway, I had some realizations doing it:
  • Having 2 image formats is needlessly complex
  • Software blitting sucks (esp. alpha blending from a 8888 to a 1555 image)
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. I'll now try to completely understand the blend.c and rendertarget.c gu samples and report back ;)

Oh, and here's a (not very impressive) screenshot:
Image
chaos
Posts: 135
Joined: Sun Apr 10, 2005 5:05 pm

Post by chaos »

looks like you might beat shine to the punch :)

good luck to you both!
Chaosmachine Studios: High Quality Homebrew.
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Re: Alpha blending, hardware acceleration

Post by Shine »

Durante 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.
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=3399
Durante
Posts: 65
Joined: Sun Oct 02, 2005 6:07 am
Location: Austria

Re: Alpha blending, hardware acceleration

Post by Durante »

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.
Yes, software blitting is really slow with 8888, especially alpha blending.
Shine wrote:My future plans are to integrate pspgl for OpenGL support, which provides all graphics formats, ...
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
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Re: Alpha blending, hardware acceleration

Post by Shine »

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?
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.
Koba
Posts: 59
Joined: Thu Sep 29, 2005 10:57 am

Post by Koba »

this is what i have been waiting for, now for shine to find a way to make this 100% work and lua will have taken another step towards awsomeness ;)
Durante
Posts: 65
Joined: Sun Oct 02, 2005 6:07 am
Location: Austria

Post by Durante »

Ok, I said I'd look into it and I did, but it took a bit longer than expected ;) - but mostly because I just started yesterday, not because of any inherent difficulty.

Anyway, I now have an pspGL based LuaPlayer version that can blit images to the screen. Woohoo. But, in the process I broke everything else (graphics related). Also, blitting/drawing to images with h/w acceleration will probably not be possible until RTT is implemented in pspGL. Therefore, you'd need a software fallback for that. Perhaps VFPU based? Well, I'll not implement it, as I don't need it ;)

I also broke the screenshot function (of course!) so here's an exceedingly crappy webcam shot:
Image

Next, I'll try to fix the line and rect drawing functions, and add a scaled/rotated blit (fairly trivial to implement).
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

Durante wrote:Anyway, I now have an pspGL based LuaPlayer version that can blit images to the screen. Woohoo.
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 :-)

The current version: http://www.frank-buss.de/tmp/LuaPlayer-opengl.zip

Currently my version is 0.10 based, if possible update first the latest Lua Player from SVN and copy the OpenGL bindings to it. You can send me the result to [email protected], if you like, I'll test it and commit it to SVN. Thanks for your work for Lua Player.

A script for the OpenGL version (looks like lightning crashes, so it doesn't look as nice as http://www.frank-buss.de/java3d/ , but I've not tested it with the latest pspgl version)

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
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

Durante wrote:I also broke the screenshot function (of course!) so here's an exceedingly crappy webcam shot:
For screenshots you can intergrate this code to the Lua Player OpenGL version.
Durante
Posts: 65
Joined: Sun Oct 02, 2005 6:07 am
Location: Austria

Post by Durante »

Hmm, I switched to an 8888 image format (remember, alpha blending is the reason I'm doing all of this ;)) and added various ugly hackish debugging stuff, so I don't believe that a complete merger is a good idea currently.

I'll just post the relevant code here - it's not that much.
First off, the initialization:

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;
}
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.

For symmetry:

Code: Select all

void disableGraphics()
{
	eglTerminate(g_egl_dpy);
	initialized = 0;
}
Blitting then works like this:

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);
}
Of course, you should not use immediate mode in production code but rather use vertex buffers -- though in this case it shouldn't matter too much. Also, you'd need to use the GL_UNSIGNED_SHORT_1_5_5_5_REV format as indicated in the comment. The first 3 lines should probably be extracted from this method.

Rects and lines (which I just implemented):

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();
}
with

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)); 
}
Here you'd need to adjust the R,G,B,A macros for the 1555 format.

Finally, clearing and flipping:

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));
}
And that's it basically. Now if you can find a way to intelligently decide automagically which textures to put into VRAM... ;)
Durante
Posts: 65
Joined: Sun Oct 02, 2005 6:07 am
Location: Austria

Post by Durante »

Just after posting I noticed that I'm not yet using the source rectangle specification, but that's not much of a problem. Will do it now.

[edit] Done & tested:

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();
}
[edit2]
And here's a small script that tests all the supported features:

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()
Durante
Posts: 65
Joined: Sun Oct 02, 2005 6:07 am
Location: Austria

Post by Durante »

Just noticed that I can implement the colors far more elegantly:

Code: Select all

static inline void gl_colorize(color) 
{
	glColor4ubv(&color);
}
Progress:
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!
Zenurb
Posts: 106
Joined: Fri Sep 30, 2005 8:33 am
Location: United Kingdom
Contact:

Post by Zenurb »

Durante wrote:Just noticed that I can implement the colors far more elegantly:

Code: Select all

static inline void gl_colorize(color) 
{
	glColor4ubv(&color);
}
Progress:
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!
Are you going to make your gl version open to public?
Proud Dvorak User
US 1.5 PSP (Original)
Durante
Posts: 65
Joined: Sun Oct 02, 2005 6:07 am
Location: Austria

Post by Durante »

Zenurb wrote:Are you going to make your gl version open to public?
Sure! Do you want it? ;)
I just believe that Shine will integrate this stuff into the main version sooner or later (and probably do a better job at it!) and I don't want to fork LuaPlayer, so I won't do anything like an official release. That also wouldn't be very interesting for non-developers, as many conventional programs are slower in my version.
Zenurb
Posts: 106
Joined: Fri Sep 30, 2005 8:33 am
Location: United Kingdom
Contact:

Post by Zenurb »

of course, forking luaplayer would be a bad idea. however if you released it to the public (so shine could take a look at it) it may speed the developing process.
Proud Dvorak User
US 1.5 PSP (Original)
Durante
Posts: 65
Joined: Sun Oct 02, 2005 6:07 am
Location: Austria

Post by Durante »

Here are all the changed source files (if svn is right ;))
DL me if you dare

To compile:
1. get the goop pspgl version ( http://www.goop.org/psp/gl/ )
2. get the current svn LuaPlayer
3. update the makefile (Makefile.psp.common) to point to the goop lib and include paths and add -lGL and -lGLU
(alternatively, just replace the svn GL libs and headers in you usr/local/psp/..)
4. replace the files in the src directory with those in my zip
5. >make install

For reference, here's the relevant parts of my Makefile.psp.common:

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
If any of you actually try this, please let me know how it went! (Also try the testing script I posted up there somewhere if you want to see alpha blending)
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

Thanks for your implementations. Do you have changed the image structure to 32 bit, only? Would be nice to have all pixel formats. Perhaps you can send me the code and I'll try to merge it (with a flag in the image struct), so that we have at least 8888 and 5551.
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.
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.

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 :-)
Durante
Posts: 65
Joined: Sun Oct 02, 2005 6:07 am
Location: Austria

Post by Durante »

Shine wrote:Thanks for your implementations. Do you have changed the image structure to 32 bit, only?
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: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 :-)
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!

Though I'd use some image distance measure to compare for validity with distance < some epsilon instead of the checksum, as the OpenGL result must not necessarily be exactly the same as the software rendered one.
Durante
Posts: 65
Joined: Sun Oct 02, 2005 6:07 am
Location: Austria

Post by Durante »

I'm terribly productive today ;) - guess what I implemented:
Image

That's right, I fixed/reimplemented image saving, and added 3 new screen functions:

Code: Select all

nil screen.blitScaled&#40;x, y, Image source, scalex, scaley, &#91;sourcex, sourcey, width, height&#93;&#41;
nil screen.blitRotated&#40;x, y, Image source, angle, &#91;sourcex, sourcey, width, height&#93;&#41;
nil screen.blitRotScale&#40;x, y, Image source, angle, scalex, scaley, &#91;sourcex, sourcey, width, height&#93;&#41;
This is the screenshot generator:

Code: Select all

img = Image.load&#40;"test.png"&#41;
buff = Image.createEmpty&#40;128, 64&#41;

buff&#58;blit&#40;0, 0, img&#41;
buff&#58;blit&#40;64, 0, img&#41;

screen&#58;clear&#40;Color.new&#40;0,128,128&#41;&#41;

screen&#58;blit&#40;0, 0, img&#41;
screen&#58;blit&#40;128, 0, img, 16, 16, 32, 32&#41;
screen.blitScaled&#40;200, 0, img, 0.5, 2.5&#41;
screen.blitRotated&#40;170, 150, img, 33.3&#41;
screen.blitRotScale&#40;320, 150, img, 45.0, 0.7, 1.4&#41;;
screen&#58;blit&#40;0, 90, buff&#41;

screen&#58;fillRect&#40;0, 180, 32, 32, Color.new&#40;255, 0, 0&#41;&#41;
screen&#58;fillRect&#40;32, 180, 32, 32, Color.new&#40;0, 255, 0&#41;&#41;
screen&#58;fillRect&#40;0, 212, 32, 32, Color.new&#40;0, 0, 255&#41;&#41;

for pos=0,255 do 
	screen&#58;drawLine&#40;480-255+pos, pos, 480, 0, Color.new&#40;pos, 255-pos, 0&#41;&#41;
end

screen.flip&#40;&#41;
screen&#58;save&#40;"shot.png"&#41;

while not Controls.read&#40;&#41;&#58;start&#40;&#41; do end
The new source package:
http://peter.metaclassofnil.com/stuff/p ... 5-2105.zip
nevyn
Posts: 136
Joined: Sun Jul 31, 2005 5:05 pm
Location: Sweden
Contact:

Post by nevyn »

Dude, Durante, you are awesome. I'm thinking you oughta have commit access or something.

I don't like your API, but then again, that's why I'm the API guy ;) I'll wait until your stuff is in the repos, and I'll probably change the api like so:


(rotation) Image:rotation([(rotation)newRotation]) // means: returns the old rotation value, takes an optional argument which will set a new rotation
{(scale),(scale)} Image:scale([{(scale)scalex, (scale)scaley}])

The calls to the different functions will then be done behind the scenes if needed.
Durante
Posts: 65
Joined: Sun Oct 02, 2005 6:07 am
Location: Austria

Post by Durante »

nevyn wrote:I don't like your API
I don't even like it myself! Your proposal is indeed much better. The blit functions have enough arguments as is ;)
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):

Code: Select all

unsigned r = CLAMP&#40;luaL_checkint&#40;L, 1&#41;, 0, 255&#41;; 
unsigned g = CLAMP&#40;luaL_checkint&#40;L, 2&#41;, 0, 255&#41;; 
unsigned b = CLAMP&#40;luaL_checkint&#40;L, 3&#41;, 0, 255&#41;;
unsigned a;
if &#40;argc == 4&#41; &#123;
	a = CLAMP&#40;luaL_checkint&#40;L, 3&#41;, 0, 255&#41;; // EVIL
&#125; else &#123;
	a = 255;
&#125;
Took me some time to figure THAT out. Copy & paste's a bitch.
nevyn
Posts: 136
Joined: Sun Jul 31, 2005 5:05 pm
Location: Sweden
Contact:

Post by nevyn »

Durante wrote:
nevyn wrote:I don't like your API
I don't even like it myself! Your proposal is indeed much better. The blit functions have enough arguments as is ;)
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):

Code: Select all

unsigned r = CLAMP&#40;luaL_checkint&#40;L, 1&#41;, 0, 255&#41;; 
unsigned g = CLAMP&#40;luaL_checkint&#40;L, 2&#41;, 0, 255&#41;; 
unsigned b = CLAMP&#40;luaL_checkint&#40;L, 3&#41;, 0, 255&#41;;
unsigned a;
if &#40;argc == 4&#41; &#123;
	a = CLAMP&#40;luaL_checkint&#40;L, 3&#41;, 0, 255&#41;; // EVIL
&#125; else &#123;
	a = 255;
&#125;
Took me some time to figure THAT out. Copy & paste's a bitch.
Haha. Sorry about that... Looks like code I've been responsible for.

Well, blitting to image should keep rotation and scaling as well... I spoke with Shine about the rotation stuff. He's porting Cairo instead, which will bring us rotation, scaling, primitives, and a hell of a lot of other stuff. Probably throwing out all the old Image stuff. We might break the API, but what the hey . . . :P
Durante
Posts: 65
Joined: Sun Oct 02, 2005 6:07 am
Location: Austria

Post by Durante »

Well, if he can get Cairo to work fast enough on the PSP that would be great, but I don't believ that's easy or even non-hard ;). Anyway, I'll just continue to use my local version for developing my game until something better comes along that supports everything I need -- it's not like rewriting the Lua code would be much work.

Another possibility I thought about for implementing fast alpha blending / rotation / scaling from image to image would be to get the target image in the framebuffer, render to it and copy the result back. Not a terribly great solution, but probably still faster than doing it in software.
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

Durante wrote:32 bit only, mostly for simplicity.
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.

Another problem are the pspgl implementations. The goop pspgl lib still freezes on my 1.00 PSP and with the pspgl version from SVN, I have some problems with the alpha blending and the texture blitting has some strange black borders (perhaps because of rounding problems, I didn't checked this in detail). So I tried the GU functions.

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. Take a look at the "splinesurface" example, to see what is possible with it. The functions are very similiar to OpenGL, which makes it easy to use it. Perhaps some API guy can design a nice Lua Player interface for it :-)

The new Lua Player is committed to SVN, but not ready for a release. Alpha blending should work, but I didn't tested it (@Durante: Please test it and send me a test case with pictures, if it doesn't work). All Lua Player programs works (but there are problems with the timer with the latest GCC 4.0.2 update). Next we should discuss how to encapsulate sceGumDrawArray. An example how to use the new 3D functions (after using it, 2D functions might not work any more until the program is restarted). It is based on the cube example from the PSPSDK, from which I needed only to strip all those nasty ".0f"s and semicolons :-)

Code: Select all

red = Color.new&#40;255, 0, 0&#41;
green = Color.new&#40;0, 255, 0&#41;
blue = Color.new&#40;0, 0, 255&#41;
black = Color.new&#40;0, 0, 0&#41;
white = Color.new&#40;255, 255, 255&#41;
cyan = Color.new&#40;100, 255, 255&#41;

val = 0

logo = Image.createEmpty&#40;64, 64&#41;
logo&#58;print&#40;20, 20, "Lua", white&#41;
logo&#58;print&#40;10, 40, "Player", white&#41;

vertices = &#123;
	&#123;u=0, v=0, color=red, x=-1, y=-1, z= 1&#125;,  -- 0
	&#123;u=1, v=0, color=red, x=-1, y= 1, z= 1&#125;,  -- 4
	&#123;u=1, v=1, color=red, x= 1, y= 1, z= 1&#125;,  -- 5

	&#123;u=0, v=0, color=red, x=-1, y=-1, z= 1&#125;,  -- 0
	&#123;u=1, v=1, color=red, x= 1, y= 1, z= 1&#125;,  -- 5
	&#123;u=0, v=1, color=red, x= 1, y=-1, z= 1&#125;,  -- 1

	&#123;u=0, v=0, color=red, x=-1, y=-1, z=-1&#125;,  -- 3
	&#123;u=1, v=0, color=red, x= 1, y=-1, z=-1&#125;,  -- 2
	&#123;u=1, v=1, color=red, x= 1, y= 1, z=-1&#125;,  -- 6

	&#123;u=0, v=0, color=red, x=-1, y=-1, z=-1&#125;,  -- 3
	&#123;u=1, v=1, color=red, x= 1, y= 1, z=-1&#125;,  -- 6
	&#123;u=0, v=1, color=red, x=-1, y= 1, z=-1&#125;,  -- 7

	&#123;u=0, v=0, color=green, x= 1, y=-1, z=-1&#125;,  -- 0
	&#123;u=1, v=0, color=green, x= 1, y=-1, z= 1&#125;,  -- 3
	&#123;u=1, v=1, color=green, x= 1, y= 1, z= 1&#125;,  -- 7

	&#123;u=0, v=0, color=green, x= 1, y=-1, z=-1&#125;,  -- 0
	&#123;u=1, v=1, color=green, x= 1, y= 1, z= 1&#125;,  -- 7
	&#123;u=0, v=1, color=green, x= 1, y= 1, z=-1&#125;,  -- 4

	&#123;u=0, v=0, color=green, x=-1, y=-1, z=-1&#125;,  -- 0
	&#123;u=1, v=0, color=green, x=-1, y= 1, z=-1&#125;,  -- 3
	&#123;u=1, v=1, color=green, x=-1, y= 1, z= 1&#125;,  -- 7

	&#123;u=0, v=0, color=green, x=-1, y=-1, z=-1&#125;,  -- 0
	&#123;u=1, v=1, color=green, x=-1, y= 1, z= 1&#125;,  -- 7
	&#123;u=0, v=1, color=green, x=-1, y=-1, z= 1&#125;,  -- 4

	&#123;u=0, v=0, color=blue, x=-1, y= 1, z=-1&#125;,  -- 0
	&#123;u=1, v=0, color=blue, x= 1, y= 1, z=-1&#125;,  -- 1
	&#123;u=1, v=1, color=blue, x= 1, y= 1, z= 1&#125;,  -- 2

	&#123;u=0, v=0, color=blue, x=-1, y= 1, z=-1&#125;,  -- 0
	&#123;u=1, v=1, color=blue, x= 1, y= 1, z= 1&#125;,  -- 2
	&#123;u=0, v=1, color=blue, x=-1, y= 1, z= 1&#125;,  -- 3

	&#123;u=0, v=0, color=blue, x=-1, y=-1, z=-1&#125;,  -- 4
	&#123;u=1, v=0, color=blue, x=-1, y=-1, z= 1&#125;,  -- 7
	&#123;u=1, v=1, color=blue, x= 1, y=-1, z= 1&#125;,  -- 6

	&#123;u=0, v=0, color=blue, x=-1, y=-1, z=-1&#125;,  -- 4
	&#123;u=1, v=1, color=blue, x= 1, y=-1, z= 1&#125;,  -- 6
	&#123;u=0, v=1, color=blue, x= 1, y=-1, z=-1&#125;,  -- 5
&#125;

while true do
	sceGuStart&#40;&#41;

	-- clear screen

	sceGuClearColor&#40;cyan&#41;
	sceGuClearDepth&#40;0&#41;;
	sceGuClear&#40;GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT&#41;

	-- setup matrices for cube

	sceGumMatrixMode&#40;GU_PROJECTION&#41;
	sceGumLoadIdentity&#40;&#41;
	sceGumPerspective&#40;75, 16/9, 0.5, 1000&#41;

	sceGumMatrixMode&#40;GU_VIEW&#41;
	sceGumLoadIdentity&#40;&#41;

	sceGumMatrixMode&#40;GU_MODEL&#41;
	sceGumLoadIdentity&#40;&#41;
	sceGumTranslate&#40;0, 0, -3.5&#41;;
	sceGumRotateXYZ&#40;val * 0.79 * &#40;GU_PI/180&#41;, val * 0.98 * &#40;GU_PI/180.0&#41;, val * 1.32 * &#40;GU_PI/180.0&#41;&#41;

	-- setup texture

	sceGuTexImage&#40;logo&#41;
	sceGuTexFunc&#40;GU_TFX_ADD, GU_TCC_RGB&#41;
	sceGuTexEnvColor&#40;Color.new&#40;0xff, 0xff, 0xff&#41;&#41;
	sceGuTexFilter&#40;GU_LINEAR, GU_LINEAR&#41;
	sceGuTexScale&#40;1, 1&#41;
	sceGuTexOffset&#40;0, 0&#41;
	sceGuAmbientColor&#40;white&#41;

	-- draw cube

	sceGumDrawArray&#40;GU_TRIANGLES, GU_TEXTURE_32BITF|GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_3D, vertices&#41;

	sceGuFinish&#40;&#41;
	sceGuSync&#40;0, 0&#41;

	val = val + 1

	if Controls.read&#40;&#41;&#58;start&#40;&#41; then break end

	screen.waitVblankStart&#40;&#41;
	screen.flip&#40;&#41;
end
sweetlilmre
Posts: 27
Joined: Sat Oct 01, 2005 7:24 pm

Stack issues with 32 bit conversion

Post by sweetlilmre »

Hi,

I've been playing with the 8888 conversion and have come across something interesting. It seems that the creation of the vertex list in graphics.c:

unsigned int __attribute__((aligned(16))) list[262144];

causes stack / compilation issues when linking against a fairly old mikmod build:

/usr/local/pspdev/lib/gcc/psp/4.0.1/../../../../psp/lib/libmikmod.a(mloader.o):
In function `ReadComment':
/home/petere/source/mikmodlib/playercode/mloader.c:58: relocation truncated to f
it: R_MIPS_GPREL16 against `modfp'

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?)

Thanks
-(e)
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Re: Stack issues with 32 bit conversion

Post by Shine »

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?)
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).

mikmod was not compiled with the -G0 option. I don't know exactly what it does, but it helps when you have large static variables :-)
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

nevyn wrote:I don't like your API, but then again, that's why I'm the API guy ;)
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.

I think we are not the first people who wants to design vertices easier and perhaps more object oriented. Does someone know good examples of libraries or architectures, where this is already implemented?
Durante
Posts: 65
Joined: Sun Oct 02, 2005 6:07 am
Location: Austria

Post by Durante »

I believe that you/we/Luaplayer should go even higher level, providing the end-user with something akin to (ideally):

Code: Select all

mything = Mesh&#58;new&#40;"mything.obj"&#41;

node = Scene.addNode&#40;1, 1, 1&#41; -- x, y, z pos

node&#58;rotate&#40;0, 1, 0, 45&#41; -- axis, angle
node&#58;scale&#40;2, 1, 1&#41; -- xyz scale factor

subnode = node&#58;addNode&#40;&#41; -- 0,0,0

mything&#58;attach&#40;subnode&#41;

Scene.render&#40;&#41;
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 ;)

An IMHO very well designed but VERY extensive 3d engine:
http://ogre3d.org/
At least part of the API would be great to steal ;)
nevyn
Posts: 136
Joined: Sun Jul 31, 2005 5:05 pm
Location: Sweden
Contact:

Post by nevyn »

I don't know 3D coding. I've just never ventured there... However, I'm taking a course on OpenGL starting this Monday. Once I get a grasp on what's involved in 3D programming, I can look at the API...
Durante wrote:I believe that you/we/Luaplayer should go even higher level, providing the end-user with something akin to (ideally):

Code: Select all

mything = Mesh&#58;new&#40;"mything.obj"&#41;

node = Scene.addNode&#40;1, 1, 1&#41; -- x, y, z pos

node&#58;rotate&#40;0, 1, 0, 45&#41; -- axis, angle
node&#58;scale&#40;2, 1, 1&#41; -- xyz scale factor

subnode = node&#58;addNode&#40;&#41; -- 0,0,0

mything&#58;attach&#40;subnode&#41;

Scene.render&#40;&#41;
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 ;)

An IMHO very well designed but VERY extensive 3d engine:
http://ogre3d.org/
At least part of the API would be great to steal ;)
Mmm, that's the kind of level I like it on :)
jsgf
Posts: 254
Joined: Tue Jul 12, 2005 11:02 am
Contact:

Post by jsgf »

Shine wrote:Another problem are the pspgl implementations. The goop pspgl lib still freezes on my 1.00 PSP
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#26557

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.
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.
Post Reply