Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

15.05.2010, 18:08

Welche API

Ich bin ein Fan davon, mehrere Sachen gleichzeitig zu programmieren. Komme ich mal mit einem Teil nicht weiter, dann mache ich beim andere Teil weiter. Nun möchte ich langsam mit dem Editor meines Spiels anfangen. Leider habe ich keine Ahnung welche API ich für die benutzeroberfläche benutzen sollte. Vieleicht die WinAPI, MFC, QT oder doch eine eigene mit OpenGl basteln?

C-/C++-Quelltext

1
2
3
4
while(true)
{
    printf("Schon wieder aufgehangen!?");
}

Beiträge: 774

Beruf: Student

  • Private Nachricht senden

2

15.05.2010, 19:03

WinAPI ist meiner Meinung nach ein bischen arg lowlevel und unhandlich. Aber natürlich durchaus zu gebrauchen.
MFC ist ja glaub ich sogar veraltet? So oder so kommen beide Optionen nicht infrage wenn du auch mal von Windows weg willst (sofern du das willst). Über Qt hab ich viel gutes gehört; mit der Visual C++ Express krieg ich das allerdings kaum hin, weil man da so ein AddIn "braucht" (express unterstützt keine AddIns... aber ich geb zu, so ganz hab ich das alles nie verstanden). Mit wxWidgets bin ich selber ganz glücklich :)

Von einem Editor in selbstgeschriebener GUI kann ich dir aus persönlciher Erfahrung abraten.. sobald der Editor komplizierter wird legt einem das schon viele Steine in den Weg. Eine selbstgeschriebene GUI in Ogl lass lieber im eignetlich Spiel arbeiten, als in irgendwelchen Tools.
Klar.. wenn du eine wirklich gute, präzise umfangreiche GUI hinkriegst (und fürs Spiel braucht man wie angemerkt ja meist eh ein wenig davon), kannst du das auch nutzen - ist nur aufwendig...

Alyx

Treue Seele

Beiträge: 236

Wohnort: Hannover

Beruf: Head Of Software Development

  • Private Nachricht senden

3

15.05.2010, 19:15

Je nachdem. Um eigene GUI-Komponenten wie Fenster, Buttons, Checkboxes & Co. kommst du auf Dauer gesehen so oder so nicht drumrum, zumindest kenne ich kein fertiggestelltes Spiel, das nicht mindestens diese Elemente direkt in der 3D-API integriert hat, allein schon zwecks Konfiguration, Level-Auswahl & Co.. Ich habe es direkt selbst entwickelt und würde es immer wieder so machen, es hat mich zwar 4 Monate gekostet, aber es hat mir zwischenzeitlich auch schon mindestens wieder einen gespart, dadurch, dass halt ich definiere was geht und vor allen Dingen auch dadurch, dass das 2D-GUI und der 3D-Engine halt so miteinander verbunden sind, dass ich problemlos überall im 2D-Bereich, sei es als Frame, sei es auf einem Button oder wo auch immer, 3D-Modelle darstellen kann wie zum Beispiel bei einer Objekt-Typ-Auswahl etc. pp., macht einfach Spaß.

LG
Alyx

4

15.05.2010, 19:33

Da hast du wohl recht, um eine GUI werde ich nicht herum kommen. Außerdem ist es ja auch eine gute Erfahrung soetwas einmal programmiert zu haben. Ich möchte schon lange entlich mal etwas "sinvolles" fertig programmiert haben. Ich glaube ich setze mich dort einfach mal dran.

Ich kann mir gut vorstellen, dass eine GUI auf eine Art Scenegraph aufbaut. Ich verschiebe ein Fenster, also verschiebe alle Child-Fenster, usw ...

Und was das Zeichnen angeht, erstelle ich einfach ein Quadrat aus 2 Dreiecken, Jage diese durch einen Shader, welcher diese untransofrmiert weiter gibt, und die Sache ist gegessen? Oder geht man bei solchen Dingen ganz anders vor?

// Edit

So, hab das nun einfach mal umgesetzt. Ich erstelle ein Vertex und Indexbuffer, welche für alle zu zeichnenden Bilder verwendet werden. Diese haben Koordinaten von 0 bis 1. Anschließend geht das ganze dann durch folgenden Shader:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int iScreenWidth  = 800;
int iScreenHeight = 600;
int iImageX     = 100;
int iImageY     = 100;
int iImageWidth   = 200;
int iImageHeight  = 200;
float4 vColor   = float4(1,1,1,1);

float4 VS(float4 inPosition : POSITION) : POSITION
{
    float sx = 2.0f/iScreenWidth;
    float sy = 2.0f/iScreenHeight; 
    
    float4 outPosition;

    outPosition.x = -1.0f+ sx*inPosition.x*iImageWidth +iImageX*sx;
    outPosition.y =  1.0f-(sy*inPosition.y*iImageHeight+iImageY*sy);
    outPosition.z = 0;
    outPosition.w = 1;

    return outPosition;
}
 
float4 PS() : COLOR
{  
    return vColor;
}


Jetzt kann man Position, Größe und Farbe durch die globalen Vars bestimmen. Im prinziep werden die Positions und größen Angaben einfach in den ViewSpace umgewandelt und die y Achse wird einmal gedreht.

Funktioniert soweit eigentlich ganz gut, weiß aber nicht, ob es nun wirklich "Die Beste" Lösung ist, bzw ob es bessere gibt. Ich möchte mich halt nich wieder Blind in ein Projekt stürzen und es dann wieder über den Haufen werfen, weil ich auf einer ganz falschen Grundlage aufgebut habe.

C-/C++-Quelltext

1
2
3
4
while(true)
{
    printf("Schon wieder aufgehangen!?");
}

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Potatoman« (16.05.2010, 01:27)


BlazeX

Alter Hase

Beiträge: 478

Wohnort: DD

Beruf: Maschinenbau-Student

  • Private Nachricht senden

5

16.05.2010, 14:46

Die "Beste Lösung" wird es nie geben. Das, was du da hat, ist schonmal ein guter Ansatz.
Versuch doch mal die globalen Daten für ein Viereck variabel von außen (vom Programm) zu setzen.
Damit kannst du dann anfangen viele Vierecke mit "Buchstabentexturen" zu rendern. Und schon kannst du Texte rendern.

Am besten ist es, wenn du dir Ziele setzt. Zum Beispiel "Eine GUI schreiben".
Was gehört zu einer GUI?
-> Es gibt Fenster, Buttons, Checkboxes, Editboxes, Scrollbars, statische Texte ...
-> Prinzip: Alles sind Fenster
Wie geht mein Programm damit um?
-> Eine Basisklasse für Fenster (Hat: Position, Größe, Childs, Parent, ...)
-> Je nach Typ (Button, ...) extra Klasse ableiten
Wie "definiert" man eine GUI?
-> Wie Windows Resourcen
--> Nein, was eigenes auf XML-Basis (XML eignet sich wirklich gut für solche Sachen!)
...

Eben alles auftriefeln, gut durchdenken, gut planen. Wenn das erledigt ist kannste losschreiben.

Oder du nimmst etwas "fertiges", wie die CEGUI.

Alyx

Treue Seele

Beiträge: 236

Wohnort: Hannover

Beruf: Head Of Software Development

  • Private Nachricht senden

6

16.05.2010, 15:32

BlazeX hats quasi schon gut zusammengefasst.

Um's mal möglichst knapp zusammen zu fassen, was du brauchst, wenn es hinterher angenehm zu bedienen sein soll:
- die Möglichkeit 2D-Grafiken zu laden und als solche zu behandeln. Sprich LoadImage -> DrawImage(X,Y) bzw. DrawImage(X,Y,ScaledWidth,ScaledHeight)
- eine 2D-Canvas-Klasse mit oben genannten Funktionen sowie stupiden Dingen wie DrawRect, DrawLine & Co.
- diese 2D-Canvas-Klasse sollte so konfigurierbar sein, dass jede Komponente später zwischen 0,0 und ihrer eigenen Width & Height zeichnen kann, sprich alle Zeichenbefehle zeichnen relative zu einem gewissen Offset (die obere linke Ecke). Im Optimalfall kann man auch den Zeichnebereich limitieren.

Da es kein Staatsgeheimnis ist, hier ein bischen von meinem Quelltext:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// Internal paint function
void AUIView::PaintInt(A2DCanvas* Canvas, bool isFxCall, AUICanvasRegion ClipRegion)
{
    AVector2DD Offset = GetOffset();
    double sw, sh; GetScalingAbsolute(sw,sh);

    if( !isFxCall )
    {   
        double  x   = Offset.mX+marRegions[0].mX*sw,
                y   = Offset.mY+marRegions[0].mY*sh,
                x2  = x+marRegions[0].mWidth*sw,
                y2  = y+marRegions[0].mHeight*sh;

        ClipRegion.LimitRegion(x,y,x2,y2);
        Canvas->SetClipping(ClipRegion.mX,ClipRegion.mY,ClipRegion.mX2,ClipRegion.mY2);
    }
    Canvas->SetOffset(Offset.mX,Offset.mY);
    Canvas->SetScaling(sw,sh);

    mlCoveredRects.Clear();
    mlVisibleRects.Clear();

    if( isFxCall )
    {       
        Canvas->SetClipping(ClipRegion.mX,ClipRegion.mY,ClipRegion.mX2,ClipRegion.mY2);
        PaintFx(Canvas);        
        return;
    }

    HandleHoverFx();
    
    //ATimer gt(true);
    CalcCoverageRects(Canvas,Offset);

    bool Covered = false;
    double  ox2 = sw*mrFrame.mWidth,
            oy2 = sh*mrFrame.mHeight;

    for( int i=0; i<~mlCoveredRects; ++i )
    {
        ARectd cur = mlCoveredRects[i];
        if( cur.mX<=0.0+0.00001 && cur.mY<=0.0+0.00001 && ox2<=cur.mX+cur.mWidth+0.00001 && oy2<=cur.mY+cur.mHeight+0.00001 )
        {
            Covered = true;
            break;
        }
    }

    ARect<double>::MultiClipRect(marRegions[0],mlCoveredRects,mlVisibleRects,Canvas->mlWorkSpaceA,Canvas->mlWorkSpaceB);

    Canvas->SetCoverageInfo(&mlCoveredRects,&mlVisibleRects);

    if( !Covered )
    {
        Paint(Canvas); // <-- eigentliche Zeichenfunktion
... 
}
    PaintChildrenInt(Canvas,Offset,ClipRegion,sw,sh);
...
...


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Paints the child components
void AUIView::PaintChildrenInt(A2DCanvas* Canvas, AVector2DD Offset, AUICanvasRegion ClipRegion, double sw, double sh)
{
    int SkipTill = 0;

    for( int i=~mlChildren-1; i>=0; --i )
    {
        if( ASetContains(mlChildren[i]->mComponentFlags,AUIComponentFlags::IsWindow) )
        {
            if( mlChildren[i]->GetWidth()==GetClientWidth() && mlChildren[i]->GetHeight()==GetClientHeight() )
            {
                SkipTill = i; break;
            }
        }
    }

    for( int i=0; i<~mlChildren; ++i )
    {
        AUIView* cc = mlChildren[i];
        if( !cc->IsVisible() )
            continue;

        if( i<SkipTill && ASetContains(cc->mComponentFlags,AUIComponentFlags::IsWindow) )
            continue;

        ARectd cf = cc->GetFrame();
        if( cf.mY>marRegions[cc->miParentRegionIndex].mHeight ||
            cf.mX>marRegions[cc->miParentRegionIndex].mWidth  ||
            cf.mY+cf.mHeight<0.0 ||
            cf.mX+cf.mWidth<0.0 )
            continue;

        AUICanvasRegion ChildRegion = ClipRegion;

        double  x   = Offset.mX+marRegions[cc->miParentRegionIndex].mX*sw,
                y   = Offset.mY+marRegions[cc->miParentRegionIndex].mY*sh,
                x2  = x+marRegions[cc->miParentRegionIndex].mWidth*sw,
                y2  = y+marRegions[cc->miParentRegionIndex].mHeight*sh;

        ChildRegion.LimitRegion(x,y,x2,y2);

        ARectd Frame = cc->GetFrame();

        if( Frame.mX>=0 && mrFrame.mY>=0 && 
            Frame.mX+Frame.mWidth<=marRegions[cc->miParentRegionIndex].mWidth && 
            Frame.mY+Frame.mHeight<=marRegions[cc->miParentRegionIndex].mHeight )
        {
            cc->mCurParentClipRegion = ClipRegion;
        }       
        else
        {
            cc->mCurParentClipRegion = ChildRegion;
        }

        cc->PaintInt(Canvas,false,ChildRegion);
    }

}


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
// Sets the clipping region
void A2DCanvas::SetClipping(double x, double y, double x2, double y2)
{
    mClipMinX = x;
    mClipMinY = y;
    mClipMaxX = x2;
    mClipMaxY = y2;
}

// .........................................................................

// Sets the drawing offset
void A2DCanvas::SetOffset(double x, double y)
{
    mXOffset = x;
    mYOffset = y;
}

...

// Slits triangle into two new triangles because just one point is outside the clipping
void SplitUpTriangle(double x, double y, double u, double v, AVector4DF color,
                     double x2, double y2, double u2, double v2, AVector4DF color2,
                     double x3, double y3, double u3, double v3, AVector4DF color3,
                     double perc21, double perc31,
                     double &nx4, double &ny4, double &nu4, double &nv4, AVector4DF &color4,
                     double &nx5, double &ny5, double &nu5, double &nv5, AVector4DF &color5)
{
    nx4         = (x-x2)*perc21+x2;
    ny4         = (y-y2)*perc21+y2;
    nu4         = (u-u2)*perc21+u2;
    nv4         = (v-v2)*perc21+v2;
    color4.mX   = (float)((color.mX-color2.mX)*perc21+color2.mX);
    color4.mY   = (float)((color.mY-color2.mY)*perc21+color2.mY);
    color4.mZ   = (float)((color.mZ-color2.mZ)*perc21+color2.mZ);
    color4.mW   = (float)((color.mW-color2.mW)*perc21+color2.mW);

    nx5         = (x-x3)*perc31+x3;
    ny5         = (y-y3)*perc31+y3;
    nu5         = (u-u3)*perc31+u3;
    nv5         = (v-v3)*perc31+v3;
    color5.mX   = (float)((color.mX-color3.mX)*perc31+color3.mX);
    color5.mY   = (float)((color.mY-color3.mY)*perc31+color3.mY);
    color5.mZ   = (float)((color.mZ-color3.mZ)*perc31+color3.mZ);
    color5.mW   = (float)((color.mW-color3.mW)*perc31+color3.mW);
}

// .........................................................................

// Shortens triangle of which 2 points are outside of the bounding
void ShortenTriangle(double x, double y, double u, double v, AVector4DF color,
                     double x2, double y2, double u2, double v2, AVector4DF color2,
                     double x3, double y3, double u3, double v3, AVector4DF color3,
                     double perc31, double perc32,
                     double &nx4, double &ny4, double &nu4, double &nv4, AVector4DF &color4,
                     double &nx5, double &ny5, double &nu5, double &nv5, AVector4DF &color5)
{
    nx4         = (x-x3)*perc31+x3;
    ny4         = (y-y3)*perc31+y3;
    nu4         = (u-u3)*perc31+u3;
    nv4         = (v-v3)*perc31+v3;
    color4.mX   = (float)((color.mX-color3.mX)*perc31+color3.mX);
    color4.mY   = (float)((color.mY-color3.mY)*perc31+color3.mY);
    color4.mZ   = (float)((color.mZ-color3.mZ)*perc31+color3.mZ);
    color4.mW   = (float)((color.mW-color3.mW)*perc31+color3.mW);

    nx5         = (x2-x3)*perc32+x3;
    ny5         = (y2-y3)*perc32+y3;
    nu5         = (u2-u3)*perc32+u3;
    nv5         = (v2-v3)*perc32+v3;
    color5.mX   = (float)((color2.mX-color3.mX)*perc32+color3.mX);
    color5.mY   = (float)((color2.mY-color3.mY)*perc32+color3.mY);
    color5.mZ   = (float)((color2.mZ-color3.mZ)*perc32+color3.mZ);
    color5.mW   = (float)((color2.mW-color3.mW)*perc32+color3.mW);
}

// .........................................................................

// Adds a triangle
void A2DCanvas::AddTriangle(    double x, double y, double u, double v, AVector4DF color,
                                double x2, double y2, double u2, double v2, AVector4DF color2,
                                double x3, double y3, double u3, double v3, AVector4DF color3,
                                bool transform, int ClipSides)
{
    if( mCurrentPrimitiveType!=A3DPrimitiveTypes::Triangles )
    {
        Flush();
        mCurrentPrimitiveType = A3DPrimitiveTypes::Triangles;
    }

    if( transform )
    {
        x *= mXScaling; x2 *= mXScaling; x3 *= mXScaling;
        y *= mYScaling; y2 *= mYScaling; y3 *= mYScaling;
        x += mXOffset;  x2 += mXOffset;  x3 += mXOffset;
        y += mYOffset;  y2 += mYOffset;  y3 += mYOffset;
    }

    // clipping check required ?
    if( x<mClipMinX || x>mClipMaxX || y<mClipMinY || y>mClipMaxY || 
        x2<mClipMinX || x2>mClipMaxX || y2<mClipMinY || y2>mClipMaxY || 
        x3<mClipMinX || x3>mClipMaxX || y3<mClipMinY || y3>mClipMaxY )
    {   
        for( int clipturn=0; clipturn<4; ++clipturn )   // for all 4 clipping sides (left,right,top,bottom)
        {   
            int ClipFlag = 1<<clipturn;

            if( ClipSides&ClipFlag )
            {       
                bool o1, o2, o3;
                switch (clipturn)
                {
                case 0: // left out
                    o1 = x  <   mClipMinX;
                    o2 = x2 <   mClipMinX;
                    o3 = x3 <   mClipMinX; break;
                case 1: // right out
                    o1 = x  >   mClipMaxX;
                    o2 = x2 >   mClipMaxX;
                    o3 = x3 >   mClipMaxX; break;
                case 2: // top out
                    o1 = y  <   mClipMinY;
                    o2 = y2 <   mClipMinY;
                    o3 = y3 <   mClipMinY; break;
                default: // bottom out
                    o1 = y  >   mClipMaxY;
                    o2 = y2 >   mClipMaxY;
                    o3 = y3 >   mClipMaxY;
                }
                
                if( o1 || o2 || o3 )
                {
                    if( o1 && o2 && o3 )    // totally out
                        return;

                    double      xc[3] = {x,x2,x3},
                                yc[3] = {y,y2,y3},
                                uc[3] = {u,u2,u3},
                                vc[3] = {v,v2,v3};
                    AVector4DF  colors[3] = {color,color2,color3};
                    bool        oc[3] = {o1,o2,o3};
                            
                    for( int i=0; i<3; ++i )
                    {
                        int i1 = i,
                            i2 = (i+1)%3,
                            i3 = (i+2)%3;

                        if( oc[i1] && !(oc[i2]||oc[i3]) )   // only 1 outside
                        {
                            double      nx4, ny4, nu4, nv4, nx5, ny5, nu5, nv5;
                            AVector4DF  color4, color5;

                            double  perc1,
                                    perc2;

                            switch( clipturn )
                            {
                            case 0: // left out
                                perc1 = (mClipMinX-xc[i2])/(xc[i1]-xc[i2]);
                                perc2 = (mClipMinX-xc[i3])/(xc[i1]-xc[i3]); break;
                            case 1: // right out
                                perc1 = (mClipMaxX-xc[i2])/(xc[i1]-xc[i2]);
                                perc2 = (mClipMaxX-xc[i3])/(xc[i1]-xc[i3]); break;
                            case 2:     // top out
                                perc1 = (mClipMinY-yc[i2])/(yc[i1]-yc[i2]);
                                perc2 = (mClipMinY-yc[i3])/(yc[i1]-yc[i3]); break;
                            default:    // bottom out
                                perc1 = (mClipMaxY-yc[i2])/(yc[i1]-yc[i2]);
                                perc2 = (mClipMaxY-yc[i3])/(yc[i1]-yc[i3]);
                            }

                            SplitUpTriangle(xc[i1],yc[i1],uc[i1],vc[i1],colors[i1],
                                            xc[i2],yc[i2],uc[i2],vc[i2],colors[i2],
                                            xc[i3],yc[i3],uc[i3],vc[i3],colors[i3],
                                            perc1,perc2,
                                            nx4,ny4,nu4,nv4,color4,nx5,ny5,nu5,nv5,color5);

                            AddTriangle(nx4,ny4,nu4,nv4,color4,xc[i2],yc[i2],uc[i2],vc[i2],colors[i2],xc[i3],yc[i3],uc[i3],vc[i3],colors[i3],false,ClipSides&~(ClipFlag));
                            AddTriangle(nx5,ny5,nu5,nv5,color5,nx4,ny4,nu4,nv4,color4,xc[i3],yc[i3],uc[i3],vc[i3],colors[i3],false,ClipSides&~(ClipFlag));

                            return;
                        }
                        if( oc[i1] && oc[i2] )              // two outside
                        {
                            double      nx4, ny4, nu4, nv4, nx5, ny5, nu5, nv5;
                            AVector4DF  color4, color5;

                            double  perc1,
                                perc2;

                            switch( clipturn )
                            {
                            case 0: // left out
                                perc1 = (mClipMinX-xc[i3])/(xc[i1]-xc[i3]);
                                perc2 = (mClipMinX-xc[i3])/(xc[i2]-xc[i3]); break;
                            case 1: // right out
                                perc1 = (mClipMaxX-xc[i3])/(xc[i1]-xc[i3]);
                                perc2 = (mClipMaxX-xc[i3])/(xc[i2]-xc[i3]); break;
                            case 2: // left out
                                perc1 = (mClipMinY-yc[i3])/(yc[i1]-yc[i3]);
                                perc2 = (mClipMinY-yc[i3])/(yc[i2]-yc[i3]); break;
                            default:    // right out
                                perc1 = (mClipMaxY-yc[i3])/(yc[i1]-yc[i3]);
                                perc2 = (mClipMaxY-yc[i3])/(yc[i2]-yc[i3]);
                            }

                            ShortenTriangle(xc[i1],yc[i1],uc[i1],vc[i1],colors[i1],
                                            xc[i2],yc[i2],uc[i2],vc[i2],colors[i2],
                                            xc[i3],yc[i3],uc[i3],vc[i3],colors[i3],
                                            perc1,perc2,nx4,ny4,nu4,nv4,color4,nx5,ny5,nu5,nv5,color5);

                            AddTriangle(nx4,ny4,nu4,nv4,color4,nx5,ny5,nu5,nv5,color5,xc[i3],yc[i3],uc[i3],vc[i3],colors[i3],false,ClipSides&~(ClipFlag));

                            return;
                        }
                    }
                }
            }
        } // of turn loop
    } // of any outside

    BYTE* Data = GetSpace(3);
    
    miCCCount += 3;

    A3DDataBuffer* cb = mlCanvasBuffers[miCurrentBuffer]->mlpDataBuffer;
    A3DDataBufferElementDescription* DBD = &cb->mvbDescription;
    
    *(AVector3DT*)&Data[DBD->miCoordOffset]     = AVector3DT((afloat)x,(afloat)y,(afloat)0);
    *(float*)&Data[DBD->maiTexSlotOffsets[0]]   = (float)u;
    *(float*)&Data[DBD->maiTexSlotOffsets[0]+4] = (float)v;
    *(AVector4DF*)&Data[DBD->miColorOffset]     = color;

    *(AVector3DT*)&Data[DBD->miCoordOffset+DBD->miSize]     = AVector3DT((afloat)x2,(afloat)y2,(afloat)0);
    *(float*)&Data[DBD->maiTexSlotOffsets[0]+DBD->miSize]   = (float)u2;
    *(float*)&Data[DBD->maiTexSlotOffsets[0]+4+DBD->miSize] = (float)v2;
    *(AVector4DF*)&Data[DBD->miColorOffset+DBD->miSize]     = color2;

    *(AVector3DT*)&Data[DBD->miCoordOffset+DBD->miSize*2]       = AVector3DT((afloat)x3,(afloat)y3,(afloat)0);
    *(float*)&Data[DBD->maiTexSlotOffsets[0]+DBD->miSize*2]     = (float)u3;
    *(float*)&Data[DBD->maiTexSlotOffsets[0]+4+DBD->miSize*2]   = (float)v3;
    *(AVector4DF*)&Data[DBD->miColorOffset+DBD->miSize*2]       = color3;
}

7

16.05.2010, 16:31

Ich weiß jetzt nicht so genau was du mit Canvas meinst, und durch den Code blicke ich auch nicht so wirklich durch, aber ich vermute mal du meinst damit, dass ein ChildWindow nur im Bereich des Parent Windows Zeichnen kann. Für sows würde ich dann ganz einfach Viewports benutzen.

Zitat

Versuch doch mal die globalen Daten für ein Viereck variabel von außen (vom Programm) zu setzen.
Mache ich denn nicht gerade genau das?

C-/C++-Quelltext

1
2
3
4
while(true)
{
    printf("Schon wieder aufgehangen!?");
}

Alyx

Treue Seele

Beiträge: 236

Wohnort: Hannover

Beruf: Head Of Software Development

  • Private Nachricht senden

8

16.05.2010, 17:32

Genau, dass du immer im entsprechenden Bereich zeichnest und mit entsprechendem Offset. Viewports kannst du dafür aus performancegründen vergessen, viel zu viele API-Calls.

Ich zeichne derzeit mit 3 Drawcalls ein komplettes Frame, wenn keine 3D-Objekte sichtbar sind. Triangles -> Flush, 2D-Linien -> Flush, übrige Dreiecke -> Flush und komme auch bei > 200 UI-Komponenten noch auf gut und gerne 1500+++ FPS. Würde ich pro Frame da 200 Viewports setzen, käme ich wahrscheinlich auf keine 100 FPS mehr, da ich ja nur für das Umsetzen des Viewports, der Matrizen etc. pp. auf > 1000 API-Calls pro Frame käme gegen derzeit vielleicht 15 bis 20.

Die Sache ist halt einfach die, dass du ja pro Komponente in der Regel 8-10, lass es bei einem Label auch mal 100 Dreiecke sein, zeichnest. Und da man ja in 99% aller Fälle die Dreiecke entweder komplett innerhalb oder komplett außerhalb zeichnet nur nur die verbleibenden 1% wirklich geclipped werden müssen, kostet es halt gefühlt gar nichts, hier selbst zu cullen.

Wenn man natürlich 3D im 2D-Bereich zeichnet selbst verständlich mit entsprechendem Viewport.

LG
Alyx

9

16.05.2010, 17:45

Also im prinziep erstellst du vor jeder Frame zwei Vertex/IndexBuffer und füllst mie dann mit den gesammten Dreiecken und Linien, und anschließend zeichnest du die ganzen Dreiecke und Linien in einem Rutsch? Ich kann mir gut vorstellen das dass bei einer GUI die keine Texturen benutzt sicherlich gut funktionieren sollte, aber jede Ecke, Seiten von Fenstern etc, bestehen aus Texturen ...

C-/C++-Quelltext

1
2
3
4
while(true)
{
    printf("Schon wieder aufgehangen!?");
}

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Potatoman« (16.05.2010, 18:15)


Alyx

Treue Seele

Beiträge: 236

Wohnort: Hannover

Beruf: Head Of Software Development

  • Private Nachricht senden

10

16.05.2010, 23:14

3 Drawcalls (ohne 3D-Vorschau): http://www.theneposproject.de/diary/gfx/Alpha3Pre.jpg

Atlas-Textur heißt das Zauberwort. :-) Sämtliche UI-Grafiken und Standard-Schriftarten werden erst in einer Liste gesammelt, anschließend werden sämtliche Mini-Texturen so angeordnet, dabei ggf. auch rotiert (90°), dass sie eine Textur möglichst perfekt ausfüllen. Als Handle wird eine virtuelle Textur zurückgeliefert, die sich verhält wie eine eigenständige, in Wirklichkeit aber nur einen Teil in einer großen repräsentiert.

Um nur in Farbe zu zeichnen, werden als UV-Werte 0.0,0.0 übergeben, die ohne Pixelshader (OpenGL < 2.0) auf ein weißes Pixel zeigen, mit Pixel-Shader direkt 1.0/1.0/1.0/1.0 als Farbwert verwenden.

Wie du schon richtig gesagt hast, werden die gecullten Dreiecke in einem VB gesammelt, die Atlas-Textur sowie der Shader angewählt, wobei das bei einer Ausgabe ohne Linien immer der Fall ist, und pro Frame dann eigentlich immer nur noch die Buffer geflushed. Die Buffer werden immer in 65k Blöcken allokiert, um zu älteren Grafikkarten kompatibel zu bleiben. Sprich wenn der erste voll werden sollte, wird ein zweiter allokiert usw..

Bei temporären Texturen wie Nicht-Standard-Schrifarten, Logos o.ä. würde je ein weiterer DrawCall fällig. Wenn man es perfekt machen wollte, könnte man hier ein intelligentes Defragmentierungs-System bauen, dass zur Laufzeit die Texturen immer wie neu anordnet, aber da es recht viel Aufwand wäre und es gut läuft wie es läuft, habe ich mir das gespart.

Was auch sehr sehr viel gebracht hat, war das Ermitteln von Verdeckungen. Sprich "Desktop -> Fenster das 3/4 des Desktops verdeckt" macht es natürlich wenig Sinn alles zu füllen. Entsprechend wird jedes Element gegen seine Verdecker geclipped, so dass am Ende eine Liste der noch sichtbaren Rechtecke übrig bleibt, die dann auch nur gefüllt werden. Bei Objekten mit runden Ecken etc. darf man natürlich nur den Part werten, der komplett füllend ist. Generell macht es auch nur ab einer gewissen Größe Sinn, da sonst das Clipping teurer ist als die Füllrate, die man spart. Ab 100x100 macht es ca. Sinn, sprich flächendeckende Fenster, Frames etc..

LG
Alyx

Werbeanzeige