Du må være registrert og logget inn for å kunne legge ut innlegg på freak.no
X
LOGG INN
... eller du kan registrere deg nå
Dette nettstedet er avhengig av annonseinntekter for å holde driften og videre utvikling igang. Vi liker ikke reklame heller, men alternativene er ikke mange. Vær snill å vurder å slå av annonseblokkering, eller å abonnere på en reklamefri utgave av nettstedet.
  10 2907
Jeg lurer altså på om det er mulig å tegne på skjermen med Python, da tenker jeg på eksempelvis linjer som er synlige på skjermen, og som ligger over alle andre vinduer slik at de ikke forsvinner selvom jeg tar opp et nytt vindu.

Jeg har sett at man har noen libraries man kan bruke til å tegne i, eksempelvis PyDraw, problemet med disse er at man må lage et vindu som man tegner i. Jeg ønsker ikke et eget vindu å tegne i, jeg vil tegne "på skjermen", altså over alle andre vinduer jeg har åpne i Windows.

Slenger ved noe pseudo-kode for å vise hva jeg ser for meg:

Kode

#Importer fiktivt library
import MagiskTegneLib as mtl

#Hent skjermstørrelse
screenSize = mtl.getScreenSize() #Result: [1280,720]
#Definer posisjon for senter av skjermen, og øverste venstre hjørne
drawPos1 = [(screenSize[0] / 2), (screenSize[1] / 2)] #Result: [640,360]
drawPos2 = [0, screenSize[1]] #Result: [0,720]
#Tegn en strek mellom de to punktene jeg har definert
myLine = mtl.drawLine(start=drawPos1, end=drawPos2, color=blue, thickness=0.5)
#Fjern linjen vi akkurt lagde
myLine.clear()

Er det noen som vet om det finnes et slikt library? Eller enellerannen måte å gjøre dette på?
Har du testet wxpython sin ScreenDC()?

Et alternativ er også å lage et vindu som er like stort som skjermen og gjennomsiktig, og spesifisere at dette ikke skal ha noen rammer. Hvis du har tenkt å tegne på skjermen og så gå over til å bruke programmene i bakgrunnen så vil det derimot funke ganske dårlig.
Sist endret av Dyret; 23. august 2016 kl. 12:13.
m0b
m0b's Avatar
DonorAdministrator
From top of my head: jeg ser for meg et par løsninger som kan gjøre dette, men jeg vet ikke hvor enkelt det vil være å få til på et skikkelig vis i python, du vil i all hovedssak trenge å kommunisere med APIene i windows. wxPython, imagewi og/eller winapi librariene tror jeg vil ha tilgang til de metodene du trenger.

* Hent ut hdc (null) fra hwnd og bruk grafikkobjektet til å tegne til desktopen. I dette tilfellet vil det du ha tegnet inn forsvinne dersom det aktuelle området blir tegnet på nytt av operativsystemet, så du er nødt til å cache det og tegne på nytt enten ved nye frames eller at du setter opp en metode for å finne ut om pixlene i et gitt område har endret seg fra tidligere frames.

* Opprett et borderless vindu med samme størrelse som screenbufferet, sett transparency på det og bring det fram i front. Koble deg inn i OnPaint-eventen, hent ut DC, opprett en pen og brush og bruk disse til å tegne i vinduet (DrawLine, DrawRectangle osv).

Kommer litt ann på hva bruksområdet ditt er, og om du fortsatt har tenkt til å bruke de andre vinduene samtidig. Kan være du må trikse litt med et ikkefirkantig (SetWindowRgn) overlay vindu i kombinasjon med transparency.

Edit: Fant en gammel tråd jeg svarte i for noen år siden, som gjør noe lignende du spør etter. Den tegner en roterende opengl dings til "desktop". https://freak.no/forum/showthread.php?p=1457342
Sist endret av m0b; 23. august 2016 kl. 12:20.
Sitat av Dyret Vis innlegg
Har du testet wxpython sin ScreenDC()?

Et alternativ er også å lage et vindu som er like stort som skjermen og gjennomsiktig, og spesifisere at dette ikke skal ha noen rammer. Hvis du har tenkt å tegne på skjermen og så gå over til å bruke programmene i bakgrunnen så vil det derimot funke ganske dårlig.
Vis hele sitatet...
Tusen takk for svar Det var smart med et transparent bakgrunnsvindu, men om dette forhindrer meg i å jobbe som vanlig på PCen så fungerer det dessverre ikke

Det finnes jo programmer som lar deg tegne på skjermen, gjør det ikke? Folk bruker jo dette når de lager tutorials, hvor de kan lage skisser hvorsomhelst på skjermen. Ligger begrensningen på Python da kanskje? Er dette mulig med andre programmeringsspråk?

Sitat av |d13m0b Vis innlegg
*snip*
Vis hele sitatet...
Takker og bukker Se der ja, dette virker jo langt mer omfattende enn hva jeg hadde sett for meg Hmm, kanskje det finnes et annet program som allerede kan gjøre dette, og som jeg kan calle fra Python med cmd-kommandoer f.eks?
Sist endret av simchris; 23. august 2016 kl. 12:25. Grunn: Automatisk sammenslåing med etterfølgende innlegg.
m0b
m0b's Avatar
DonorAdministrator
Sitat av simchris Vis innlegg
Takker og bukker Se der ja, dette virker jo langt mer omfattende enn hva jeg hadde sett for meg Hmm, kanskje det finnes et annet program som allerede kan gjøre dette, og som jeg kan calle fra Python med cmd-kommandoer f.eks?
Vis hele sitatet...
Fant ikke noe som passet med det du har beskrevet, så jeg skreiv et kjapt og gæli til deg. Ikke helt etter din kravspec, men det klarer du helt sikkert å fikse selv, samt gjøre dette om til noe mer akseptabel python. Samt fikse tykkelse og farge. Kan helt sikkert dokumentere litt valgene jeg gjør i opprettinga av vinduet (de spesifike bitmaskene), men det får eventuelt bli i morgen.

Hva med noe slikt? Resultatet er linje som ikke er interaktiv og som ikke tar i mot mouse-events. Alt som er transparent i vinduet unngår også å snappe opp events. Vinduet/linjen vil alltid være i forgrunnen, bortsett fra om du kjører fullscreen applikasjon. Da må en nok hooke seg opp i directx.

Med litt kjapp omskriving av koden så kan du jo gjøre det slik at du kan enten sende inn en struktur med flere points for å tegne flere linjer, eller hente ut LineTo mm. for å lage en draw-funksjon for det. Her har du jo også gode muligheter for å lage deg en "game-loop", og utføre animasjoner. Mange muligheter her.



Du må installere pywin32 (https://sourceforge.net/projects/pywin32) for å kjøre dette.

Kode

"""
A non-euclidean, hyperdimentional, cross-platform (win/osx/linux/bsd/quantum computers/etc) 
drawing package with extendend support for brownian motions and impossible colours - myoxocephalus
"""

import win32api, win32con, win32gui

class m0bsMagiskeTegneLib:
	def __init__(self, x0, y0, x1, y1):
		self.x0, self.y0, self.x1, self.y1 =  x0, y0, x1, y1

		self.wndClass = win32gui.WNDCLASS()
		self.wndClass.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW
		self.wndClass.lpfnWndProc = self.wndProc
		self.wndClass.hInstance = win32api.GetModuleHandle()
		self.wndClass.hCursor = win32gui.LoadCursor(None, win32con.IDC_ARROW)
		self.wndClass.hbrBackground = win32gui.GetStockObject(win32con.WHITE_BRUSH)
		self.wndClass.lpszClassName = "TransparentNonInteractiveWindow"

		self.hWindow = win32gui.CreateWindowEx(
			win32con.WS_EX_COMPOSITED | win32con.WS_EX_LAYERED | win32con.WS_EX_NOACTIVATE | win32con.WS_EX_TOPMOST | win32con.WS_EX_TRANSPARENT,
			win32gui.RegisterClass(self.wndClass),
			None,
			win32con.WS_DISABLED | win32con.WS_POPUP | win32con.WS_VISIBLE,
			0,
			0,
			win32api.GetSystemMetrics(win32con.SM_CXSCREEN),
			win32api.GetSystemMetrics(win32con.SM_CYSCREEN),
			None,
			None,
			self.wndClass.hInstance,
			None
		)
		win32gui.SetLayeredWindowAttributes(self.hWindow, 0x00ffffff, 255, win32con.LWA_COLORKEY | win32con.LWA_ALPHA)
		win32gui.SetWindowPos(self.hWindow, win32con.HWND_TOPMOST, 0, 0, 0, 0,
		win32con.SWP_NOACTIVATE | win32con.SWP_NOMOVE | win32con.SWP_NOSIZE | win32con.SWP_SHOWWINDOW)
		win32gui.PumpMessages()

	@staticmethod
	def getScreenSize():
		return win32api.GetSystemMetrics(win32con.SM_CXSCREEN), win32api.GetSystemMetrics(win32con.SM_CYSCREEN)
	
	def wndProc(self, hWnd, message, wParam, lParam):
		if message == win32con.WM_PAINT:
			hdc, paint = win32gui.BeginPaint(hWnd)

			self.x0, self.y0 = win32gui.ScreenToClient(hWnd, (self.x0, self.y0))
			self.x1, self.y1 = win32gui.ScreenToClient(hWnd, (self.x1, self.y1))

			pen = win32gui.CreatePen(win32con.PS_SOLID, 5, win32api.RGB(255,0,0))
			win32gui.SelectObject(hdc, pen)

			win32gui.MoveToEx(hdc, self.x0, self.y0)
			win32gui.LineTo(hdc, self.x1, self.y1)
			win32gui.ReleaseDC(hWnd,hdc)

			win32gui.EndPaint(hWnd, paint)
			return 0

		elif message == win32con.WM_DESTROY:
			win32gui.PostQuitMessage(0)
			return 0

		else:
			return win32gui.DefWindowProc(hWnd, message, wParam, lParam)


if __name__ == '__main__':
	screenSize = m0bsMagiskeTegneLib.getScreenSize()
	m0bsMagiskeTegneLib(0, (screenSize[1]/2), screenSize[0], (screenSize[1]/2))
Nytt innlegg:
Jeg skreiv en liten update. Et lite problem med forrige implementasjon er at du ikke vil kunne tegne opp flere linjer ved å kalle drawLine-metoden flere ganger, løser det ved å threade createWindow-metoden slik at callbacken og følgelig render-metoden kjøres separat fra drawLine. Ved andre kjøring av drawLine vil den sjekke om vinduet er initialisert og om det er det, så vil den invalidere vinduet slik at man får en ny WM_PAINT-message.

Denne implementasjonen lager et kryss over hele skjermen.

Kode

"""
A non-euclidean, hyperdimentional, cross-platform (win/osx/linux/bsd/quantum computers/etc) 
drawing package with extendend support for brownian motions and impossible colours - myoxocephalus
"""

import win32api
import win32con
import win32gui
from threading import Thread

class m0bsMagiskeTegneLib(object):
    def __init__(self):
        self.lines = []
        self.initialized = False
        Thread(target=self.createWindow).start() # Yolo

    def createWindow(self):
        self.wndClass = win32gui.WNDCLASS()
        self.wndClass.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW
        self.wndClass.lpfnWndProc = self.wndProc
        self.wndClass.hInstance = win32api.GetModuleHandle()
        self.wndClass.hCursor = win32gui.LoadCursor(None, win32con.IDC_ARROW)
        self.wndClass.hbrBackground = win32gui.GetStockObject(win32con.WHITE_BRUSH)
        self.wndClass.lpszClassName = "TransparentNonInteractiveWindow"

        self.hWindow = win32gui.CreateWindowEx(
            win32con.WS_EX_COMPOSITED | win32con.WS_EX_LAYERED | win32con.WS_EX_NOACTIVATE | win32con.WS_EX_TOPMOST | win32con.WS_EX_TRANSPARENT,
            win32gui.RegisterClass(self.wndClass),
            None,
            win32con.WS_DISABLED | win32con.WS_POPUP | win32con.WS_VISIBLE,
            0,
            0,
            win32api.GetSystemMetrics(win32con.SM_CXSCREEN),
            win32api.GetSystemMetrics(win32con.SM_CYSCREEN),
            None,
            None,
            self.wndClass.hInstance,
            None)
        win32gui.SetLayeredWindowAttributes(self.hWindow, 0x00ffffff, 255, win32con.LWA_COLORKEY | win32con.LWA_ALPHA)
        win32gui.SetWindowPos(self.hWindow, win32con.HWND_TOPMOST, 0, 0, 0, 0,
                              win32con.SWP_NOACTIVATE | win32con.SWP_NOMOVE | win32con.SWP_NOSIZE | win32con.SWP_SHOWWINDOW)
        win32gui.PumpMessages()
        self.initialized = True

    @staticmethod
    def getScreenSize():
        return win32api.GetSystemMetrics(win32con.SM_CXSCREEN), win32api.GetSystemMetrics(win32con.SM_CYSCREEN)

    def drawLine(self, start, end, color, width):
        line = {'start' : start, 'end' : end, 'color' : color, 'width' : width }
        self.lines.append(line)

        if self.initialized:
            win32gui.InvalidateRect(self.hWnd, None, True)
            win32gui.UpdateWindow(self.hWnd)

    def toScreenCoord(self, hWnd, start, end):
        return win32gui.ScreenToClient(hWnd, (start[0], start[1])), win32gui.ScreenToClient(hWnd, (end[0], end[1]))

    def render(self, hWnd):
        for line in self.lines:            
            (x0, y0), (x1, y1) = self.toScreenCoord(hWnd, line['start'], line['end'])

            pen = win32gui.CreatePen(win32con.PS_SOLID, line['width'], win32api.RGB(line['color'][0], line['color'][1], line['color'][2]))
            win32gui.SelectObject(self.hdc, pen)
            win32gui.MoveToEx(self.hdc, x0, y0)
            win32gui.LineTo(self.hdc, x1, y1)

    def wndProc(self, hWnd, message, wParam, lParam):
        if message == win32con.WM_PAINT:
            self.hdc, paint = win32gui.BeginPaint(hWnd)

            self.render(hWnd)
            
            win32gui.ReleaseDC(hWnd, self.hdc)
            win32gui.EndPaint(hWnd, paint)
            return 0

        elif message == win32con.WM_DESTROY:
            win32gui.PostQuitMessage(0)
            return 0

        else:
            return win32gui.DefWindowProc(hWnd, message, wParam, lParam)


if __name__ == '__main__':
    # Hent skjermstørrelse
    screenSize = m0bsMagiskeTegneLib.getScreenSize()
    drawPos0 = [0, 0] # Venstre, Topp
    drawPos1 = [screenSize[0], screenSize[1]] # Høyre, Bunn
    drawPos2 = [screenSize[0], 0] # Høyre, Topp
    drawPos3 = [0, screenSize[1]] # Venstre, Bunn

    mtl = m0bsMagiskeTegneLib()
    mtl.drawLine(start=drawPos0, end=drawPos1, color=(255, 0, 0), width=5)
    mtl.drawLine(start=drawPos2, end=drawPos3, color=(255, 0, 0), width=5)
Sist endret av m0b; 25. august 2016 kl. 13:48. Grunn: Automatisk sammenslåing med etterfølgende innlegg.
▼ ... over en uke senere ... ▼
|d13m0b: Oi, har ikke fått med meg svaret ditt før nå, tusen takk! Jeg skal prøve dette når jeg kommer hjem, spent på å teste! Takker og bukker

Oppdatering: Jeg fikk testet på laptopen nå, det fungerte akkurat som jeg håpte det ville gjøre! Du er genial!
Sist endret av simchris; 4. september 2016 kl. 04:08. Grunn: Automatisk sammenslåing med etterfølgende innlegg.
Scriptet fungerer perfekt, bortsett fra ett lite mysterium. Dersom det går for lang tid mellom hver gang fnDrawLine calles så resulterer det i at ingenting tegnes opp. Har lagt ved et eksempel nedenfor:

Kode

"""
A non-euclidean, hyperdimentional, cross-platform (win/osx/linux/bsd/quantum computers/etc) 
drawing package with extendend support for brownian motions and impossible colours - myoxocephalus
|d13m0b
"""

# IMPORT MODULES
import win32api
import win32con
import win32gui
from threading import Thread

# CREATE CLASS
class DrawingLib(object):
    # Constructor
    def __init__(self):
        # Declare instance variables
        self.lines = []
        self.initialized = False
        # Open the window in a thread
        Thread(target=self.fnCreateWindow).start()


    # Function: Create the window
    def fnCreateWindow(self):
        # Register the window class
        self.wndClass = win32gui.WNDCLASS()
        self.wndClass.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW
        self.wndClass.lpfnWndProc = self.fnWndProc
        self.wndClass.hInstance = win32api.GetModuleHandle()
        self.wndClass.hCursor = win32gui.LoadCursor(None, win32con.IDC_ARROW)
        self.wndClass.hbrBackground = win32gui.GetStockObject(win32con.WHITE_BRUSH)
        self.wndClass.lpszClassName = "TransparentNonInteractiveWindow"

        # Declare variables for the window style settings
        vDwExStyle = win32con.WS_EX_COMPOSITED | win32con.WS_EX_LAYERED | win32con.WS_EX_NOACTIVATE | win32con.WS_EX_TOPMOST | win32con.WS_EX_TRANSPARENT
        vClassName = win32gui.RegisterClass(self.wndClass)
        vStyle = win32con.WS_DISABLED | win32con.WS_POPUP | win32con.WS_VISIBLE
        vWidth = win32api.GetSystemMetrics(win32con.SM_CXSCREEN)
        vHeight = win32api.GetSystemMetrics(win32con.SM_CYSCREEN)
        vHInstance = self.wndClass.hInstance
        # Creates a new window with Extended Style: (dwExStyle,className,windowTitle,style,x,y,width,height,parent,menu,hinstance,reserved)
        self.hWindow = win32gui.CreateWindowEx(vDwExStyle, vClassName, None, vStyle, 0, 0, vWidth, vHeight, None, None, vHInstance, None)

        # Set window attributes
        win32gui.SetLayeredWindowAttributes(self.hWindow, 0x00ffffff, 255, win32con.LWA_COLORKEY | win32con.LWA_ALPHA)
        win32gui.SetWindowPos(self.hWindow, win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOACTIVATE | win32con.SWP_NOMOVE | win32con.SWP_NOSIZE | win32con.SWP_SHOWWINDOW)
        win32gui.PumpMessages()

        # Set the initialized bool to True
        self.initialized = True


    # Declare the function below as a static method, as this will only return information
    @staticmethod
    # Function: Return the screen size
    def fnGetScreenSize():
        return win32api.GetSystemMetrics(win32con.SM_CXSCREEN), win32api.GetSystemMetrics(win32con.SM_CYSCREEN)


    # Function: Function used to draw lines on the screen
    def fnDrawLine(self, start, end, color, width):
        # Pass the input data into a dictionary
        newLine = {'start' : start, 'end' : end, 'color' : color, 'width' : width }
        # Append the data to the instance variable
        self.lines.append(newLine)
        # If the window is initialized
        if self.initialized:
            # Redraw the window with the updated line data
            win32gui.InvalidateRect(self.hWnd, None, True)
            win32gui.UpdateWindow(self.hWnd)


    # Function: Convert line data to valid screen coordinates
    def fnToScreenCoord(self, hWnd, start, end):
        return win32gui.ScreenToClient(hWnd, (start[0], start[1])), win32gui.ScreenToClient(hWnd, (end[0], end[1]))


    # Function: Render the window
    def fnRender(self, hWnd):
        # For each line specified
        for line in self.lines:
            # Convert the data of the current lines into valid screen coordinates
            (x0, y0), (x1, y1) = self.fnToScreenCoord(hWnd, line['start'], line['end'])
            # Initialize a pen with the specified width and color for the current line
            penDraw = win32gui.CreatePen(win32con.PS_SOLID, line['width'], win32api.RGB(line['color'][0], line['color'][1], line['color'][2]))
            # Select the initialized pen
            win32gui.SelectObject(self.hdc, penDraw)
            # Specify start position of the current line
            win32gui.MoveToEx(self.hdc, x0, y0)
            # Specify and draw to the end position of the current line
            win32gui.LineTo(self.hdc, x1, y1)


    # Function: Remove all of the drawings on the screen
    def fnClearScreen(self):
        # Clear the line data
        self.lines = []
        # If the window is initialized
        if self.initialized:
            # Redraw the window with the updated line data
            win32gui.InvalidateRect(self.hWnd, None, True)
            win32gui.UpdateWindow(self.hWnd)


    # Function: The window procedure function
    def fnWndProc(self, hWnd, message, wParam, lParam):
        # If the window procedure message equals win32con.WM_PAINT
        if message == win32con.WM_PAINT:
            # Begin painting
            self.hdc, paint = win32gui.BeginPaint(hWnd)
            self.fnRender(hWnd)
            win32gui.ReleaseDC(hWnd, self.hdc)
            win32gui.EndPaint(hWnd, paint)
            return 0

        # If the window procedure message equals win32con.WM_DESTROY
        elif message == win32con.WM_DESTROY:
            # Destroy the window
            win32gui.PostQuitMessage(0)
            return 0

        # Else
        else:
            # Make background transparent
            return win32gui.DefWindowProc(hWnd, message, wParam, lParam)


# Create a class instance
mtl = DrawingLib()
# Loop from 0-100
for x in range(0,100):
    # Pause for 0.1 second
    time.sleep(0.1)
    # Clear the screen
    mtl.fnClearScreen()
    # Draw a new line
    mtl.fnDrawLine(start=[0, 500 + x], end=[900, 300], color=(255, 0, 0), width=5)
Nå har jeg brukt time.sleep for å trigge feilen, men man får det samme problemet dersom man kjører andre funksjoner i mellomtiden som tar for lang tid. Har du noen anelse om hvorfor dette skjer? Eventuelt en løsning? Har forøvrig prøvd meg på å kommentere koden for å se om jeg forstår hvordan det funker, men har nok bommet litt her og der :P

Ja, glemte å ta med import time når jeg limte inn her, har det i koden min her så det er ikke det som er problemet dersom noen skulle tro det
Sist endret av simchris; 7. september 2016 kl. 03:02. Grunn: Automatisk sammenslåing med etterfølgende innlegg.
Jeg har ikke hatt muligheter til å kjøre det du har modifisert enda, men det som slår meg her er at: Når du slenger inn sleep i fnDrawLine, så er det det å legge linjene i "disse skal rendres", så dersom render-metoden er ferdigkjørt før du har fått lagt inn linjene, vil du jo ikke se noe. Er det animering av linjen(e) du ønsker å oppnå? I så fall tror jeg at jeg ville fått render-loopen til å kjøres kontinuerlig ved å la den invalidere, og så justere loopen til antall fps som er ønskelig.

Noe ala dette

Kode

    # Function: The window procedure function
    def fnWndProc(self, hWnd, message, wParam, lParam):
        # If the window procedure message equals win32con.WM_PAINT
        if message == win32con.WM_PAINT:

            # Begin painting
            self.hdc, paint = win32gui.BeginPaint(hWnd)
            self.fnRender(hWnd)

            win32gui.ReleaseDC(hWnd, self.hdc)
            win32gui.EndPaint(hWnd, paint)
 
            # Self invalidate - continuous game loop
            win32gui.InvalidateRect(hWnd, None, True)
            win32gui.UpdateWindow(hWnd)
            fps = 30
            time.sleep(1.0/fps)            
            return 0
Sist endret av m0b; 7. september 2016 kl. 12:02.
Sitat av |d13m0b Vis innlegg
*snip*
Vis hele sitatet...
Og her har jeg sitti og revet meg i håret for å forstå hvordan jeg skulle løse det, kun et par linjer skulle til Tusen takk for all hjelp mister! Det fungerte perfekt
Ingen problem! Hvis dette er noe du har tenkt å arbeide videre med, så kan det være en grei tanke å ha i bakhodet at metoden som er brukt for å tegne her ikke nødvendigvis er de mest optimale rent syklusmessig. Dersom du har tenkt å gjøre noe mer avansert så kan det være en idé å begynne å se på grafikkprogrammering i OpenGL eller lignende. OpenGL kan du bruke som erstatning for å tegne i det usynlige vinduet, og det vil være langt mer effektivt i form av å plotte pixler. Du vil sannsynligvis også finne mye mer god informasjon på konkrete problemstillinger da det er mye brukt (til rendering), enn det som blir brukt i dette eksemplet.

Hvis du har videre spørsmål, så er det bare å fyre løs så kan jeg (eller andre) forsøke å enten hjelpe til med implementering eller forklaring.
Ja, jeg må si jeg kvier meg litt for å kaste meg inn i OpenGL :P Foreløpig så ser imidlertid løsningen din ut til å fungere perfekt Tusen takk igjen, gode tips!