# bilder performant und unhässlich skalliert darstellen?



## asarnil (4. Mrz 2009)

Hallo comunity,

hab mich grade registriert, also erstmal einen Gruß in die Runde.

Ich hab da ein Problem mit der Performance von einem meiner Javaprojekte: Es geht um ein gui für so etwas wie ein Brettspiel. Ein Bild sagt mehr als 1000 worte deshalb erstmal Screenshots:











Ich lasse derzeit für jeder der Welten (die runden Scheiben inkl. der Raumschiffe) eine Grafik im voraus zeichnen und im Arbeitsspeicher ablegen. Der untere Screenshot zeigt die native Auflösung, und damit auch die maximale gewünschte Zoomstufe. Was ich jetz gerne implementiert hätte wäre eine Methode die mir die welten performant mit beliebiger zoomstufe/bildausschnitt in mein Applet zeichnet.

Mit bruteforce (also bei jedem Frame die Welten per drawimage() an die passende stelle zu zeichnen) klappt es überhauptnicht.

Ich denke ich bin da konzeptionell voll auf dem Holzweg und deshalb will ich euch fragen, wie man so etwas vllt so performant hinkriegt, dass am Ende sogar sanfte Zoomübergänge möglich wären.


----------



## Ebenius (4. Mrz 2009)

Ich würde wohl vollständig auf die Images verzichten und gleich zeichnen. Habe schon wesentlich komplexere Dinge auf wesentlich langsameren Rechnern (als heute üblich) gezeichnet und erwarte da keine Probleme.

Ebenius


----------



## asarnil (4. Mrz 2009)

du meinst alles mit "malen nach zahlen"? ich benutze halt derzeit externe Grafiken für die Rohstoffe und die Schiffe z.B.. Ich verstehe das jetzt so, dass ich für jedes Bild dass ich bisher als png vorliegen habe, eine Methode baue, die mir aus den grund-Zeichenfunktionen das entsprechende Objekt in beliebiger Größe an eine beliebige Position im Applet zeichnet. Das derzeitige grafische Niveau könnte ich bestimmt mit shapes realisieren, aber ich befürchte hinterher könnten mir dann die Hände etwas gebunden sein, wenn ich es grafisch ausarbeiten will.

Aber ich werde es jetzt mal ausprobieren, wieviel Performance das bringt.


----------



## Ebenius (4. Mrz 2009)

Achso... Die Screenshots sahen mir so aus, als ob Du sie direkt in ein Image gezeichnet hättest. Wie wäre es denn mit skalierbaren Bildern für die Rohstoffe? Hab in Java noch nicht mit SVG gearbeitet, aber das geht doch bestimmt total hübsch, oder?

Ebenius


----------



## Wolfgang Lenhard (4. Mrz 2009)

Ich empfehle "On-the-fly-Scaling" direkt bei Anzeige mit entsprechenden RenderingHints (VALUE_INTERPOLATION_BICUBIC, falls höchste Qualität gewünscht ist): java.net: The Perils of Image.getScaledInstance(). Wenn Du es bereits so gemacht hast und es nicht klappt, dann hast Du ein Problem. Es ist nämlich die effizienteste Möglichkeit, Bilder skaliert anzuzeigen (Bug ID: 6196792 Update Image.getScaledInstance with acceleration or documentation)
Wenn das nicht klappt, dann wirst Du vermutlich wirklich direkt mit Graphics2D zeichnen müssen. Das braucht dann tatsächlich sehr wenige Ressourcen.

P.S.: Was noch hilfreich sein könnte: Einschränkung des Zeichen-Bereichs mit Graphics2D.setClip()


----------



## Fu3L (4. Mrz 2009)

asarnil hat gesagt.:


> du meinst alles mit "malen nach zahlen"? ich benutze halt derzeit externe Grafiken für die Rohstoffe und die Schiffe z.B.. Ich verstehe das jetzt so, dass ich für jedes Bild dass ich bisher *als png* vorliegen habe, eine Methode baue, die mir aus den grund-Zeichenfunktionen das entsprechende Objekt in beliebiger Größe an eine beliebige Position im Applet zeichnet. Das derzeitige grafische Niveau könnte ich bestimmt mit shapes realisieren, aber ich befürchte hinterher könnten mir dann die Hände etwas gebunden sein, wenn ich es grafisch ausarbeiten will.
> 
> Aber ich werde es jetzt mal ausprobieren, wieviel Performance das bringt.



Wenn du auf PNG verzichten kannst, benutze kein PNG. Hatte auch mal hier wegen nem Performanceproblem gefragt und die Ursache war einfach, dass das Zeichnen von PNG-Bildern wohl sehr aufwendig sein muss.

Dadurch das ich das Hintergrundbild in jpg abgespeichert und verwendet hab und nichmehr in png, bin ich von ner Prozessorauslastung von 100% auf ~10% runtergekommen...


----------



## Marco13 (4. Mrz 2009)

Letzteres könnte damit zusammenhängen, dass PNG Transparenz unterstützt, und er deswegen aufwändigst mit Transparenzberechnungen rumwurschtelt (auch wenn keine Transparenz im Bild enthalten ist!)

Die Geschwindigkeit... OK ... ggf. kannst du etwas "cachen". Die Bilder könnten einmal in Originalauflösung vorliegen, und einmal passend zur aktuellen Zoomstufe ... Im Pseudocode

```
Image original = ...
Image scaled = ..

public void paint()
{
    if (istFürDieAktuelleZoomStufeNICHTPassend(scaled))
    {
        scaled = machePassendFürAktuellenZoom();
    }
    g.drawImage(scaled);
}
```
... aber mußt halt erstmal überlegen, ob das für dich OK ist. ("Flüssiges" reinzoomen geht damit auch nicht, weil sich dann ja bei jedem neuzeichnen die Größe ändern würde...)


----------



## Ebenius (4. Mrz 2009)

Was Fuel3 da schreibt, ergibt schon Sinn. Manchmal bekommt man die Geschwindigkeit dadurch erhöht, dass man die gemalten Bilder in ein neues BufferedImage des geeigneten Typs zeichnet.

Ebenius


----------



## 0x7F800000 (4. Mrz 2009)

Und wenn du weder die Hardware mit OpenGL o.ä. , noch die (wohl ebenfalls recht effizienten) Zeichenroutinen des Graphics 2D nutzen willst, deine Grafiken aber in einer recht hohen auflösung vorliegen, dann erzeuge dennoch mipmaps! ist ja vom prinzip her sehr billig, wenn da aber 500 "Raumschiffe" zeichnen willst, und dazu pro frame 50 verschiedene bilder von 512x512px auf 10x10 px runterskalieren musst, muss es einfach irgendwann mal ruckeln. Mit mipmaps wird dies aber ziemlich sicher vermieden.


----------



## asarnil (4. Mrz 2009)

Vielen Dank erstmal für die zahlreichen anregungen!



> Letzteres könnte damit zusammenhängen, dass PNG Transparenz unterstützt, und er deswegen aufwändigst mit Transparenzberechnungen rumwurschtelt (auch wenn keine Transparenz im Bild enthalten ist!)



Ich benutze transparente pngs, und brauche auch die transparenz, weil der hintergrund zB der Rohstoffe von die Playerfarbe sein soll.



> Ich empfehle "On-the-fly-Scaling" direkt bei Anzeige mit entsprechenden RenderingHints (VALUE_INTERPOLATION_BICUBIC, falls höchste Qualität gewünscht ist)



Hab ich alles durchprobiert 



> Wenn das nicht klappt, dann wirst Du vermutlich wirklich direkt mit Graphics2D zeichnen müssen. Das braucht dann tatsächlich sehr wenige Ressourcen.



Das werde ich bald mal ausprobieren, das wird aber einiges an Programmierzeit brauchen (zumindest für meine Maßstäbe).



> ..., dann erzeuge dennoch mipmaps!



Das habe ich gemacht (ohne zu wissen was mipmaps sind). Hat auch was gebracht, aber leider nicht genug.

Das Spiel um dass es geht ist ein play-by-email-game sprich man bekommt ein turnsheet per mail, welches mein gui hübsch darstellen soll. Daraufhin schreibt man seine Befehle für die Runde zurück und wartet auf die nächste mail. Dadurch ist der darzustellende Inhalt extrem statisch. Imgrunde könnte ich ein großes jpg rendern lassen und den rest meinem Bildervorschauprogramm überlassen. Ich will aber durch clicken auf bestimmte stellen auf dieser Karte Dinge passieren lasse (z.B. Befehle in ein textfenster schreiben oder metainfo über die Welten anzeigen lassen)

Deshalb denke ich darüber nach mich mit meinem gui mehr an googlemaps zu orientieren. Dass immer ein etwa passender Screenshot der Karte im Buffer ist und dieser ab und zu aktualisiert wird. Dieser Screenshot wird dann immer entsprechend der aktuellen kameraeinstellung zurechtgeschnitten.


----------



## Wolfgang Lenhard (4. Mrz 2009)

Und wie wäre es mit VolatileImage? Das nehme ich in Animationen. Die Grafikdaten lagern dann direkt im Speicher der Grafikkarte.


----------

