Code:
well I know the nvidia quadro4 cards are meant for up to 4
monitors, is that what you're doing now is hooking the projectors
to the video card? If so, any slicing and dicing of the images
would have to be done at a near OS level (on in the case of *nix,
the window manager level).
Not true.
If you are using something like Direct3D to render or OpenGL simply get a pointer to the render buffer. In D3D you would get a pointer to the back buffer (attached surface; secondary buffer) and a pointer to the main or primary buffer.
You will have to have a very large image otherwise the pixels will break down into blocks in each of the 4 images.
This is NOT optimized. Using temporaries from C in assembly code results in significant performance loss - as was pointed out to me by Fordy.
Code:
//Code assumes you want 4 equally sized pictures
struct QuadBuffer
{
DWORD *Screen1;
DWORD *Screen2;
DWORD *Screen3;
DWORD *Screen4;
};
void SplitScreen4(int resx,int resy,QuadBuffer ReturnBuffer)
{
//D3D - get attached surface
//Get pointer to secondary and primary buffer.
//This is barring SURFACEDESC.memPitch in DirectX
//Assumes a 32-bit color buffer using DWORDs
//Get pointer to back buffer or render buffer
DWORD *SourceBuffer=<function to get pointer to secondary
buffer>;
//4 images will be half the size on x and y as the original
WORD buf_sizex=resx>>1;
WORD buf_sizey=resy>>1;
DWORD buf_totalsize=(buf_sizex*buf_sizey)<<2;
//Allocate memory for buffers
DWORD *temp1=NULL;
DWORD *temp2=NULL;
DWORD *temp3=NULL;
DWORD *temp4=NULL;
ReturnBuffer.Screen1=new DWORD[buf_totalsize];
ReturnBuffer.Screen2=new DWORD[buf_totalsize];
ReturnBuffer.Screen3=new DWORD[buf_totalsize];
ReturnBuffer.Screen4=new DWORD[buf_totalsize];
temp1=&ReturnBuffer.Screen1;
temp2=&ReturnBuffer.Screen2;
temp3=&ReturnBuffer.Screen3;
temp4=&ReturnBuffer.Screen4;
//Number of bytes in one line of a buffer(2048 horz res)
DWORD bytesinoneline=8192;
//Save important registers and setup Source pointer
asm
{
push ds
push esi
push edi
lds esi,[SourceBuffer]
}
SAVEDATA:
//Save screen
//Top left corner
SCREEN1PREP:
asm
{
les edi,[temp1]
push esi
mov ecx,[bytesinoneline]
xor eax,eax
}
SCREEN1SAVEDATA:
asm
{
rep stosd
add esi,02000h
inc eax
cmp eax,[buf_totalsize]
jb SCREEN1SAVEDATA
pop esi //restore esi
}
/************************************************/
//Top right corner
SCREEN2PREP:
asm
{
les edi,[temp2]
push esi
add esi,02000h
mov ecx,[bytesinoneline]
xor eax,eax
}
SCREEN2SAVEDATA:
asm
{
rep stosd
add esi,02000h
inc eax
cmp eax,[buf_totalsize]
jb SCREEN2SAVEDATA
pop esi //restore esi
}
/***********************************************/
//Bottom left corner
SCREEN3PREP:
asm
{
les edi,[temp3]
push esi
add esi,02000000h
mov ecx,[bytesinoneline]
xor eax,eax
}
SCREEN3SAVEDATA:
asm
{
rep stosd
add esi,02000h
inc eax
cmp eax,[buf_totalsize]
jb SCREEN3SAVEDATA
pop esi //restore esi
}
/*********************************************/
//Bottom right corner
SCREEN4PREP:
asm
{
les edi,[temp4]
push esi
add esi,02002000h
mov ecx,[bytesinoneline]
xor eax,eax
}
SCREEN4SAVEDATA:
asm
{
rep stosd
add esi,02000h
inc eax
cmp eax,[buf_totalsize]
jb SCREEN4SAVEDATA
pop esi //restore esi
}
//We are done
DONE:
asm
{
//Clean up
pop edi
pop esi
pop ds
}
/************************************************/
}
This has NOT been tested and I coded it from scratch here on the board. However the principle will work. I'm simply iterating through the source buffer non-linearily. The reason I have to add is to avoid doing a mul in every loop. I'm simply using a trick to get ESI to be correct. I'm not positive that all this works as is..but its close.
You could do this in C with loops but it would be slow. You could port it to use memcpy() instead of all the asm. The reason for the labels is that MSVC, BC45, TC, and DJGPP will not jump to labels that are inside of asm blocks - they are not interpreted as labels. So you must end your asm block to use labels which looks ugly...but it gets the job done.
This is a task suited for assembly since it involves many copies to and from memory. If you can get the above code to work all you simply need to do on each video card you use is to render the buffers in the struct. The temp pointers are simply because compilers do not allow you to access structure members or class members in asm blocks - which is stupid. They say it will work but I've never gotten it to.
This is not optimized and does not make good use of the stack but it is clearer that way. This will create 4 screens from one huge one which is what you wanted....I assume.
And this is for x86 platforms only of course...but you could port it to anything.