Created
July 31, 2009 02:27
-
-
Save oneup/159051 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
NOTE:_ | |
as releasing this i don't even know how it works, | |
but maybe it helps people wondering about C# Inter Process Communications (IPC) via TCP & System.Runtime.InteropServices.Marshal.Copy | |
it has too many copies. needs to be more zero-copy-esque | |
NEEDS | |
Tao SDL | |
--- | |
DONE | |
opengl composition manager | |
clients schicken updates übers netz (ganzes bild) | |
TODO next | |
bpp unabhängig | |
resize (messages runter zu client schicken) | |
TODO | |
bpp unabhängig | |
resize | |
messages zu client und rauf | |
lazy updating (nur opengl calls, wenns was neues gibt) | |
lazy network traffic (nur geänderte sachen schicken / in textur uploaden) | |
WIE FUNZT DAS? | |
WMMain hat zwei threads | |
opengl zeichnen | |
warten auf neue clients | |
jeder client bekommt seinen eigenen thread (ClientThread) | |
der is state basiert | |
wartet auf resize messages und image daten (ruf dann window.updateTexture auf) | |
jeder client hat sein eigenes window | |
malt sich (und updated texturen) per draw() (wird vom opengl wmmain thread aufgerufen) | |
WAS IST VERBESSERUNGSWÜRDIG? | |
texturen uploaden - es wird eine riesieg leere textur neu erstellt beim ersten mal | |
texturen sind sehr grafik ram verschwenderisch (->power of two) | |
texturen werden immer komplett geupdated (nicht power of two, aber der ganze sichtbare bereich) | |
es gibt für einmal updaten ewig viele memory copies (unmanaged to managed in client, network copy client->server, managed to unmanaged in server, unmanaged to opengl) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//// | |
//// OpenGL based server that streams images to screen from multiple clients | |
//// maybe someone can use this / have fun playing with it | |
using System; | |
using System.Text; | |
using System.Collections; | |
using System.Threading; | |
using System.IO; | |
using System.Net.Sockets; | |
using System.Drawing; | |
namespace WM | |
{ | |
enum ClientThreadState | |
{ | |
WindowSize, | |
WindowData | |
} | |
class ClientThread | |
{ | |
private bool stop = false; | |
public bool running = false; | |
private TcpClient connection = null; | |
private Window w = null; | |
private ClientThreadState state = ClientThreadState.WindowSize; | |
private Rectangle winrect; | |
private Thread t = null; | |
public ClientThread ( TcpClient connection) | |
{ | |
this.connection = connection; | |
this.w = w; | |
Console.WriteLine("Client!!"); | |
t = new Thread ( new ThreadStart ( Run ) ); | |
t.Start (); | |
} | |
public void Run () | |
{ | |
this.running = true; | |
Stream outStream = this.connection.GetStream (); | |
Stream inStream = this.connection.GetStream(); | |
bool loop = true; | |
while ( loop ) | |
{ | |
try | |
{ | |
switch(state) | |
{ | |
case ClientThreadState.WindowSize: | |
Console.WriteLine("get size"); | |
StreamReader strStream = new StreamReader ( connection.GetStream () ); | |
String size = strStream.ReadLine (); | |
Console.WriteLine("size: " + size); | |
string[] sizes = size.Split('|'); | |
winrect = new Rectangle(int.Parse(sizes[0]), int.Parse(sizes[1]), int.Parse(sizes[2]), int.Parse(sizes[3])); | |
state = ClientThreadState.WindowData; | |
break; | |
case ClientThreadState.WindowData: | |
byte[] blub = new byte[winrect.Width*winrect.Height*3]; | |
connection.ReceiveTimeout = 10; | |
int count = inStream.Read(blub, 0, winrect.Width*winrect.Height*3); | |
if(count != 0) | |
{ | |
if(w == null) | |
{ | |
w = new Window(winrect, blub); | |
WMMain.getWM().addWindow(w); | |
} | |
else | |
{ | |
w.updateTexture(blub); | |
} | |
} | |
break; | |
} | |
Thread.Sleep(10); | |
loop = !this.stop; | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine(e.ToString()); | |
loop = false; | |
} | |
} | |
this.connection.Close (); | |
this.running = false; | |
WMMain.getWM().removeWindow(w); | |
} | |
public void Stop() | |
{ | |
stop = true; | |
Console.WriteLine("STOPPING"); | |
// t.Interrupt(); | |
t.Abort(); | |
connection.Close(); | |
this.running = false; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//// | |
//// OpenGL based server that streams images to screen from multiple clients | |
//// maybe someone can use this / have fun playing with it | |
using System; | |
using SdlDotNet; | |
using Tao.Sdl; | |
using Tao.OpenGl; | |
using System.Drawing; | |
namespace WM | |
{ | |
public class OpenGlWM | |
{ | |
private Surface screen; | |
private const int width = 800; | |
private const int height = 600; | |
private const int bpp = 32; | |
public OpenGlWM() | |
{ | |
screen = Video.SetVideoModeWindowOpenGL(width, height, true); | |
reshape(); | |
Gl.glPushAttrib(Gl.GL_COLOR_BUFFER_BIT); | |
Gl.glPushAttrib(Gl.GL_ENABLE_BIT); | |
Gl.glDisable(Gl.GL_DEPTH_TEST); | |
Gl.glDisable(Gl.GL_CULL_FACE); | |
Gl.glEnable(Gl.GL_TEXTURE_2D); | |
Gl.glEnable(Gl.GL_BLEND); | |
Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA); | |
Gl.glTexEnvf(Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, Gl.GL_MODULATE); | |
Gl.glColor3f(1,1,1); | |
} | |
public void reshape() | |
{ | |
Gl.glViewport(0,0,width, height); | |
Gl.glMatrixMode(Gl.GL_PROJECTION); | |
Gl.glLoadIdentity(); | |
Gl.glOrtho(0, width, height, 0, 0, 1); | |
Gl.glMatrixMode(Gl.GL_MODELVIEW); | |
Gl.glLoadIdentity(); | |
} | |
public void toggleFullscreen() | |
{ | |
if(screen.FullScreen == true) | |
screen = Video.SetVideoModeWindowOpenGL(width, height, true); | |
else | |
screen = Video.SetVideoModeOpenGL(width, height, bpp); | |
reshape(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//// | |
//// OpenGL based server that streams images to screen from multiple clients | |
//// maybe someone can use this / have fun playing with it | |
using System; | |
using SdlDotNet; | |
using Tao.Sdl; | |
using Tao.OpenGl; | |
using System.Drawing; | |
using System.Text; | |
namespace WM | |
{ | |
public class Window | |
{ | |
private static int nextPowerOfTwo(int input) | |
{ | |
--input; | |
input |= input >> 16; | |
input |= input >> 8; | |
input |= input >> 4; | |
input |= input >> 2; | |
input |= input >> 1; | |
return input + 1; | |
} | |
private bool update; //upload new texture | |
private uint []texture = new uint[1]; | |
private Rectangle winrect; //position in wm (note: rambuffer height/width will be the next power of two) | |
private float texcoordw; | |
private float texcoordh; | |
private IntPtr rambuffer = IntPtr.Zero; //backbuffer in RAM, note that the real window size (w, h) might differ from the rambuffer size (as opengl texture width/height needs to be a power of two for reasonable performance) | |
private bool newtexture = true; | |
private int texw, texh; | |
public Window(Rectangle winrect, byte[] imagedata) | |
{ | |
//WARNING - this is called in a seperate thread - DO NOT CALL OPENGL functions here. | |
this.winrect = winrect; | |
//resize to opengl texture size | |
texw = nextPowerOfTwo(winrect.Width); | |
texh = nextPowerOfTwo(winrect.Height); | |
texcoordw = (float)winrect.Width / texw; | |
texcoordh = (float)winrect.Height / texh; | |
Console.WriteLine("Surface restretch - " + winrect.Width + "|" + winrect.Height + " -> " + texw + "|" + texh); | |
rambuffer = System.Runtime.InteropServices.Marshal.AllocHGlobal(winrect.Width*winrect.Height*3); | |
//TODO: free rambuffer on destruction | |
updateTexture(imagedata); | |
} | |
public void updateTexture(byte[] newtextdata) | |
{ | |
System.Runtime.InteropServices.Marshal.Copy(newtextdata, 0, rambuffer, winrect.Width*winrect.Height*3); | |
update = true; | |
} | |
public void draw() | |
{ | |
if(update) | |
{ | |
if(newtexture) | |
{ | |
Gl.glGenTextures(1, texture); | |
Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture[0]); | |
IntPtr initialtexture = System.Runtime.InteropServices.Marshal.AllocHGlobal(texw*texh*3); | |
Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, (int)Gl.GL_RGB8, texw, texh, | |
0, Gl.GL_BGR_EXT, Gl.GL_UNSIGNED_BYTE, initialtexture); | |
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST); // Linear Filtering | |
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST); // Linear Filtering | |
System.Runtime.InteropServices.Marshal.FreeHGlobal(initialtexture); | |
newtexture = false; | |
} | |
else | |
{ | |
Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture[0]); | |
} | |
int i = Timer.TicksElapsed; | |
Gl.glTexSubImage2D(Gl.GL_TEXTURE_2D, 0, | |
//x, y | |
0, 0, winrect.Width, winrect.Height, Gl.GL_BGR_EXT, Gl.GL_UNSIGNED_BYTE, rambuffer); | |
Console.WriteLine("GLERROR: " + Gl.glGetError()); | |
i = Timer.TicksElapsed - i; | |
Console.WriteLine("Image from network - upload time: " + i); | |
Console.WriteLine("Update finished @ " + System.DateTime.Now.Ticks + " aka " + System.DateTime.Now.Millisecond); | |
update = false; | |
} | |
Gl.glEnable(Gl.GL_TEXTURE_2D); | |
Gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |
Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture[0]); | |
Gl.glBegin(Gl.GL_QUADS); | |
Gl.glTexCoord2f(0,texcoordh); | |
Gl.glVertex3i(winrect.X+0, winrect.Y+0, 0); | |
Gl.glTexCoord2f(texcoordw,texcoordh); | |
Gl.glVertex3i(winrect.X+winrect.Width, winrect.Y+0, 0); | |
Gl.glTexCoord2f(texcoordw,0); | |
Gl.glVertex3i(winrect.X+winrect.Width, winrect.Y+winrect.Height, 0); | |
Gl.glTexCoord2f(0,0); | |
Gl.glVertex3i(winrect.X+0, winrect.Y+winrect.Height, 0); | |
Gl.glEnd(); | |
Gl.glDisable(Gl.GL_TEXTURE_2D); | |
} | |
public bool hit(int x, int y) | |
{ | |
if(x >= winrect.X && x <= winrect.X + winrect.Width | |
&& y >= winrect.Y && y <= winrect.Y + winrect.Width) | |
return true; | |
else | |
return false; | |
} | |
public void moveTo(int x, int y) | |
{ | |
winrect.X = x; | |
winrect.Y = y; | |
} | |
public int getX() | |
{ | |
return winrect.X; | |
} | |
public int getY() | |
{ | |
return winrect.Y; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//// | |
//// a client i wrote ages ago, sends images via TCP Sockets | |
//// maybe someone can use this | |
using System; | |
using System.IO; | |
using System.Net.Sockets; | |
using System.Text; | |
using System.Collections; | |
using System.Threading; | |
using System.Drawing; | |
using System.Runtime.InteropServices; | |
public class WMClient | |
{ | |
public static void Main () | |
{ | |
int x = 10; | |
int y = 50; | |
TcpClient c = new TcpClient ( "localhost", 1337 ); | |
StreamReader inStream = new StreamReader ( c.GetStream () ); | |
Stream outStream = c.GetStream (); | |
String filename = "bla.bmp"; | |
Bitmap image = new Bitmap(filename); | |
image.RotateFlip(RotateFlipType.RotateNoneFlipY); | |
System.Drawing.Imaging.BitmapData [] bitmapdata = new System.Drawing.Imaging.BitmapData[2]; | |
Rectangle rect = new Rectangle(0, 0, image.Width, image.Height); | |
bitmapdata[0] = image.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, | |
System.Drawing.Imaging.PixelFormat.Format24bppRgb); | |
Bitmap image2 = new Bitmap("test.bmp"); | |
image2.RotateFlip(RotateFlipType.RotateNoneFlipY); | |
bitmapdata[1] = image2.LockBits(new Rectangle(0, 0, image2.Width, image2.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, | |
System.Drawing.Imaging.PixelFormat.Format24bppRgb); | |
Byte[] bbb = Encoding.ASCII.GetBytes (x+"|"+y+"|"+image.Width+"|"+image.Height+"\n"); | |
outStream.Write ( bbb, 0, bbb.Length ); | |
Console.WriteLine("ready"); | |
string exit = ""; | |
int curen = 0; | |
long dur = -1; | |
while(exit != "e"){ | |
//exit = Console.ReadLine(); | |
if(curen == 0) | |
curen = 1; | |
else | |
curen = 0; | |
Console.WriteLine("Send @ " + System.DateTime.Now.Ticks+ " aka " + System.DateTime.Now.Millisecond); | |
long i = System.DateTime.Now.Ticks; | |
try | |
{ | |
byte[] sendBytes = new byte[image.Width*image.Height*3]; | |
System.Runtime.InteropServices.Marshal.Copy(bitmapdata[curen].Scan0, sendBytes, 0, image.Width*image.Height*3); | |
outStream.Write ( sendBytes, 0, sendBytes.Length ); | |
} | |
catch(Exception e) | |
{ | |
Console.WriteLine(e.ToString()); | |
exit = "e"; | |
} | |
dur = System.DateTime.Now.Ticks-i; | |
Console.WriteLine("Send duration: " + dur); | |
Thread.Sleep(100); | |
//Console.ReadLine(); | |
} | |
c.Close (); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using SdlDotNet; | |
using Tao.Sdl; | |
using Tao.OpenGl; | |
using System.Drawing; | |
using System.Collections; | |
using System.Threading; | |
using System.IO; | |
using System.Net.Sockets; | |
//http://gpwiki.org/index.php/C:Using_SDL_with_OpenGL | |
/* Next: | |
* wait for client() | |
* accept client() | |
* display client image() | |
* get client update | |
* | |
* jeder client bekommt einen thread (höchstwahrscheinlich) | |
* | |
* protocol: | |
* c connect | |
* WELCOME c->s 1337? | |
* READY s->c ALWAYS! | |
* CLIENT SIZE c->s x,y,w,h,bpp (später alternativ nur w,h und wm sucht platzerl aus) | |
* FORCE UPDATE s->c UPDATE | |
* SEND UPDATE c->s UPDATE | |
* c->s pixeldata | |
* QUIT s<->c QUIT | |
* | |
* */ | |
namespace WM | |
{ | |
enum WMState | |
{ | |
NOTHING, | |
DRAGWINDOW | |
} | |
class WMMain | |
{ | |
private OpenGlWM wm; | |
private ArrayList windows = new ArrayList(); | |
private WMState state; //todo: wrap in class | |
private Window dragwindow; //todo: wrap in class with variables etc according to the current state | |
private int dragxoffset; | |
private int dragyoffset; | |
private TcpListener listener; | |
private static WMMain theOneAndOnlyWM = null; | |
public static WMMain getWM(){return theOneAndOnlyWM;} | |
private bool fin = false; | |
[STAThread] | |
static void Main(string[] args) | |
{ | |
theOneAndOnlyWM = new WMMain(); | |
WMMain.getWM().Run(); | |
} | |
public WMMain() | |
{ | |
wm = new OpenGlWM(); | |
state = WMState.NOTHING; | |
Events.Quit += new QuitEventHandler (this.Quit); | |
Events.KeyboardDown += new KeyboardEventHandler (this.KeyDown); | |
Events.MouseButtonDown += new MouseButtonEventHandler(this.MouseButton); | |
Events.MouseButtonUp += new MouseButtonEventHandler(this.MouseButton); | |
Events.MouseMotion += new MouseMotionEventHandler(this.MouseMotion); | |
listener = new TcpListener(1337); | |
listener.Start(); | |
new Thread ( new ThreadStart ( threadNetwork ) ).Start(); | |
Console.WriteLine(WMMain.getWM()); | |
} | |
private void Quit(Object sender, QuitEventArgs e) | |
{ | |
fin = true; | |
listener.Stop(); | |
} | |
public void Run() | |
{ | |
int framestart; | |
float fps; | |
int delta; | |
//bool eventhere = false; | |
while (!fin) | |
{ | |
framestart = SdlDotNet.Timer.TicksElapsed; | |
while(Events.Poll()) | |
{ | |
// eventhere = true; | |
} | |
//if(eventhere) //only draw when really necessary | |
{ | |
// Console.WriteLine("draw"); | |
DrawGLScene(); | |
// eventhere = false; | |
} | |
delta = SdlDotNet.Timer.TicksElapsed-framestart; | |
fps = delta == 0 ? 999.0f : 1000/delta; | |
Console.Write("FPS: " + fps + " Delta: " + delta + "\r"); | |
Thread.Sleep(10); | |
} | |
Console.WriteLine("");//preserves FPS string | |
theOneAndOnlyWM = null; | |
} | |
public void threadNetwork() | |
{ | |
ArrayList threads = new ArrayList (); | |
while(!fin) | |
{ | |
try | |
{ | |
TcpClient c = listener.AcceptTcpClient (); | |
threads.Add ( new ClientThread ( c ) ); | |
} | |
catch(SocketException e) | |
{ | |
Console.WriteLine(e.ToString()); | |
} | |
catch(Exception e) | |
{ | |
Console.WriteLine(e.ToString()); | |
} | |
Thread.Sleep(10); | |
} | |
Console.WriteLine("Network Stop"); | |
for ( IEnumerator e = threads.GetEnumerator (); e.MoveNext (); ) | |
{ | |
ClientThread st = (ClientThread)e.Current; | |
Console.WriteLine("stopping"); | |
st.Stop(); | |
while ( st.running ) | |
Thread.Sleep ( 100 ); | |
Console.WriteLine("STOPPED"); | |
} | |
Console.WriteLine("ALLE STOPPED"); | |
} | |
public void addWindow(Window w) | |
{ | |
windows.Add(w); | |
} | |
public void removeWindow(Window w){ | |
windows.Remove(w); | |
} | |
private void KeyDown(Object sender, KeyboardEventArgs e) | |
{ | |
switch(e.Key) | |
{ | |
case Key.Escape: | |
Quit(this, null); | |
break; | |
case Key.F1: | |
wm.toggleFullscreen(); | |
break; | |
} | |
} | |
private void MouseButton(Object sender, MouseButtonEventArgs e) | |
{ | |
if(e.ButtonPressed){ | |
if(e.Button == SdlDotNet.MouseButton.PrimaryButton) | |
{ | |
for(int i=0;i<windows.Count;i++) | |
{ | |
Window w = (Window)windows[i]; | |
if(w.hit(e.X, e.Y)) | |
{ | |
setState(WMState.DRAGWINDOW); | |
dragwindow = w; | |
dragxoffset = w.getX() - e.X; | |
dragyoffset = w.getY() - e.Y; | |
break; | |
} | |
} | |
} | |
} | |
else | |
{ | |
if(state == WMState.DRAGWINDOW) | |
{ | |
dragwindow = null; | |
setState(WMState.NOTHING); | |
} | |
} | |
} | |
private void MouseMotion(Object sender, MouseMotionEventArgs e) | |
{ | |
if(state == WMState.DRAGWINDOW) | |
{ | |
dragwindow.moveTo(e.X+dragxoffset, e.Y+dragyoffset); | |
} | |
} | |
public void DrawGLScene() | |
{ | |
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT); | |
for(int i=windows.Count-1;i>=0;i--) | |
((Window)windows[i]).draw(); | |
Video.GLSwapBuffers(); | |
} | |
private void setState(WMState newstate) | |
{ | |
//multi threading sanity check | |
state = newstate; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment