# Grafik-Engine? MemoryImageSource?



## RedNifre (4. Jul 2008)

Hallo!

Ich möchte gerne eine kleine Grafik-Engine schreiben. Nur irgendwie verstehe ich nicht so ganz, wie man das am effektivsten macht (soll ja flüssig laufen). 

Ich habe aus der Java API verstanden, dass man irgendwie mit MemoryImageSource arbeiten kann. Nur irgendwie kriege ich das überhaupt nicht zum Laufen. Und ich finde auch keine Tutorials dazu im WWW.

Es wäre echt super, wenn mir jemand ein kleines Beispiel schreiben könnte, dass das hier macht:
Minimale Implementierung für einen JFrame der bloß "rauschen" enthält, also jeder Pixel wird auf eine zufällige Farbe gesetzt und das ganze als Wiederholung (Also animiert). 

Vielen Dank!


----------



## muddin (4. Jul 2008)

Hi!

Also über die Performaz von MemoryImageSource kann ich nicht allzuviel sagen. Ich habe es mal für eine Partikel-Engine benutzt, da es recht praktisch ist, wenn man einfach ein paar Pixel setzen will. Hier mal ein Beispiel auf die Schnelle:

```
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;

public class MemImgExample extends JFrame
{
	static final int imgWidth = 640;
	static final int imgHeight = 480;
	
	int[] pixelArray = new int[imgWidth*imgHeight];
	//32-Bittiges ColorModel wenn der Alpha-Kanal auch benutzt werden soll
	//ColorModel targetCM = new DirectColorModel(32,0x00FF0000,0x000FF00,0x000000FF,0xFF000000);
	ColorModel targetCM = new DirectColorModel(24,0x00FF0000,0x000FF00,0x000000FF);
	MemoryImageSource targetMIS;
	Image targetImage;
	
	public static void main(String args[])
	{
		new MemImgExample();
	}
	
	public MemImgExample()
	{

		
		targetMIS = new MemoryImageSource(imgWidth,imgHeight,targetCM,pixelArray,0,imgWidth);
		targetMIS.setAnimated(true);
		targetMIS.setFullBufferUpdates(true);
		targetImage = createImage(targetMIS);		

		
		setSize(imgWidth,imgHeight);
		setVisible(true);
		for(int i=0;i<50;i++)
		{
			drawNoise();
			targetMIS.newPixels();
		}		
	}
	public void putPixel(int x,int y, int c)
	{
		int pos = x + (y*imgWidth);
		pixelArray[pos%(imgWidth*imgHeight)] = c;
	}
		
	private void drawNoise()
	{
		for(int y=0;y<imgHeight;y++)
			for(int x=0;x<imgWidth;x++)
			{
				putPixel(x,y,(int)(Math.random()*255*255*255));
			}
	}
	
	public void paint(Graphics g)
	{
		g.drawImage(targetImage,0,0,this);
	}
		
}
```

mfg,
Muddin


----------



## RedNifre (5. Jul 2008)

Danke, genau das hab ich gebraucht!


----------



## EgonOlsen (5. Jul 2008)

Einzelne Pixel setzen kann man aber mit einem BufferedImage, von dem man ebenfalls das Pixelarray erhalten kann. Das hat den Vorteil, dass es etwas schneller ist und man kann zusätzlich die normalen Grafikmethoden benutzen, um in das BufferedImage zu zeichnen.


----------



## RedNifre (5. Jul 2008)

BufferedImage hört sich auch interessant an.

Was genau sind denn die feinen Unterschiede zwischen MemoryImageSource und BufferedImage?
Was ist denn der beste Weg, eine flotte Grafik-Engine zu schreiben?


----------



## Marco13 (5. Jul 2008)

Hm. MemoryImageSource habe ich bisher fast nie verwendet - eigentlich kann man alles, was man damit machen kann, auch mit einem BufferedImage machen - und bei letzterem kann man (i.a.) sicher sein, dass es "managed" ist (d.h. optimiert für schnelles Zeichnen und kopieren). Ggf. solltest du mal einen direkten Vergleich zwischen beidem machen (und ggf. noch ein VolatileImage dazu, wenn's auf den letzten Funken Performance ankommt). 
Wobei mir aber auch nicht nicht klar ist, was diese "Grafikengine" können soll..........


----------



## RedNifre (5. Jul 2008)

Hier mal eine kurze Erklärung was ich vorhabe:

Abstrakt:
Eine Wolfenstein-artige Engine mit Mode7-artigem Floor/Ceiling-Texturing und Sprites. Außerdem soll die Kamera 4 echte und 1 gefakten Freiheitsgrad haben (Echt: die drei Raumbewegungen sowie Rotation um die Senkrechte Achse. Gefaked: nach oben/unten schauen).

Genauer (ohne die Optimierungsdetails):
1. Zeichne Decke und Boden Pixelweise und zwar Zeile für Zeile und jede Zeile für sich von links nach rechts.
2. Zeichne darüber die Wände und zwar Spaltenweise. Eine Texturspalte wird hierfür gestaucht/gestreckt um sie auf eine Bildschirmspalte zu zeichnen. Merke dir dabei den Orthogonalabstand zur Kamera.
3. Sortiere die sichtbaren Sprites nach Orthogonalabstand zur Kamera. Dann beginne mit dem entferntesten Sprite: Das Sprite wird spaltenweise gezeichnet, wobei für jede Spalte erst gecheckt wird, ob die Wandspalte an dieser Stelle das Sprite verdeckt oder nicht.

Es geht also darum, für jeden Frame das komplette Bild neu zu zeichnen und zwar so schnell wie möglich (Vorzugsweise 30 bis 60 FPS oder so).

Irgendwie finde ich keine Übersicht, wann man denn am besten BufferedImage/MemoryImageSource/VolatileImage benutzen sollte.


----------



## EgonOlsen (5. Jul 2008)

Für diese Geschichte musst du direkt im Pixelarray arbeiten. Das geht nur mit MI oder BI. MI ist quasi die 1.1-kompatible Variante von BI. Funktional ähnlich, aber von einem MI bekommst du keine gültige Graphics-Instanz, d.h. wenn du nicht im Array malst, sondern z.B. mit Java2D eine Linie malen willst, dann geht das mit MI nicht.
Ich würde, wenn 1.1-Unterstützung nicht erforderlich ist, immer mit BIs arbeiten. Sie sind etwas schneller, wenn auch nicht viel. In der kommenden D3D-Pipeline von Java6u10 sind beide gleich schlecht dran, also auch hier ist es egal. Du kannst auch, wenn 1.1. ein Thema sein sollte, einfach beide unterstützen. Mache ich bei jPCT im Software-Modus auch so: Wenn es 1.2+ ist, nehme ich BI. Ansonsten MI.


----------



## RedNifre (5. Jul 2008)

Vielen Dank für die Tipps! Ich habe es jetzt schon mit MemoryImageSource geschrieben, aber ich werd auch mal schauen, ob es mit dem BufferedImage besser läuft.

Hier ist ein YouTube-Video der ersten Version:
Mode7 Java Video


----------



## muddin (5. Jul 2008)

Schaut sehr nett aus


----------



## RedNifre (5. Jul 2008)

Danke!

Wenn in 100 Jahren mal ein Spiel daraus geworden sein wird werdet ihr in den Danksagungen stehen! ;-)


----------

