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

Snorky

Frischling

  • »Snorky« ist der Autor dieses Themas

Beiträge: 34

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

1

13.08.2003, 19:19

2D-Sprites für reine 2D-Grafik

Da ich zu der aussterbenden Art gehöre, die lieber 2D-Spiele programmieren als 3D (laut Forengestöber bin ich aber nicht total alleine :wink: ), fehlt mir DirectDraw in den neuesten DX-Versionen. Die Engine unterstützt das leider auch nicht so richtig, oder ich bin mal wieder blind wie sonstwas. Aber die 2D-Sprites in TriBase haben mir für reine 2D-Spiele nicht so gut gefallen und die GUI-Sachen sind in diesem Fall auch nicht so das Wahre.
:meinung:

Was mir allerdings sehr gut gefiel, war die Textengine. Da konnte man sich richtig gut ranhangeln. Also hab ich die TriBase-Engine um einen 2D-Spritebereich erweitert, der wahrscheinlich unübersehbar an Kapitel 2.12 und 3.4 angelehnt ist. Nun aber genug vorgeplänker und kommen wir gleich zum Punkt. Wer seine Engine auch erweitern möchte, sollte erstmal den TexturManager wie von mir im folgenden Thread beschrieben um die Texturformatanalyse erweitern, denn das wird hier benötigt:
http://www.scherfgen-software.net/forum/viewtopic.php?p=6735#6735

So, dann kommen jetzt die Dateien, die der Engine hinzugefügt werden:
tbINIReader, tb2DSprite und tb2DVolumeSprite. (Ja sogar 3D-Sprites kann die 2D-Engine benutzen ;D )
Alle Dateien sowohl als Header, als auch als c-Datei. Die tbINIReader enthält eigentlich nur die ganzen INI-Methoden, die in der Galactica\Game-Datei stehen. Ich fand das aber so praktischer, schließlich kann man INI-Einträge immer gebrauchen.

In die TriBase.h kommen natürlich die Header:

C-/C++-Quelltext

1
2
3
#include "tbINIReader.h"
#include "tb2DSprite.h"
#include "tb2DVolumeSprite.h"

Man beachte, dass die Volumensprites auf 2DSprite und die wiederum auf INIReader zurückgreifen, deswegen ist diese Reihenfolge recht wichtig, wenn man in den Headers die TriBase.h selbst nicht includen will.

So, kommen wir zu den eigentlichen Dateien:

Snorky

Frischling

  • »Snorky« ist der Autor dieses Themas

Beiträge: 34

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

2

13.08.2003, 19:20

tbINIReader.h

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
/********************************************************************
     _________        __    _____
    /\___  ___\      /\_\  /\  __\
    \/__/\ \__/ _  __\/_/_ \ \ \_\\   ____    _____      __
        \ \ \  /\`´__\ /\ \ \ \  __\ /\ __\_ /\  __\   /´__`\
         \ \ \ \ \ \/  \ \ \ \ \ \_\\\ \\_\ \\ \____\ /\  __/
          \ \_\ \ \_\   \ \_\ \ \____\\ \___\ \ \____\\ \____\
           \/_/  \/_/    \/_/  \/____/ \/__/   \/____/ \/____/

    tbINIReader.h
    =============
    Diese Datei ist Teil der TriBase-Engine.

    Zweck:
    Umgang mit INI-Dateien

    Autor:
    Snorky
    [13.8.2003]

********************************************************************/

#ifndef __TBINIREADER__
#define __TBINIREADER__

#pragma pack(1)


// ******************************************************************

// Klasse eines INI-Files

class TRIBASE_API tbINIReader
{
private:
    char pcFilePath[256];   // Pfad und Dateiname des INI-Files

public:
    // Konstruktor und Destruktor

    tbINIReader();
    ~tbINIReader();

    // Methoden

    tbResult    SetFilePath(char* pcINIFile);       // setzen des zu lesenden Ini-Files

    
    // Liest einen String aus der INI-Datei

    tbResult ReadINIString(char* pcSection,
                           char* pcKey,
                           char* pcOut,
                           int iBufferSize);
                                    
    // Liest einen tbColor-Wert aus der INI-Datei

    tbColor ReadINIColor(char* pcSection,
                         char* pcKey);

    // Liest einen tbVector3-Wert aus der INI-Datei

    tbVector3 ReadINIVector3(char* pcSection,
                             char* pcKey);
    
    // Liest einen float-Wert aus der INI-Datei

    float ReadINIFloat(char* pcSection,
                       char* pcKey);

    // Liest einen int-Wert aus der INI-Datei

    int ReadINIInt(char* pcSection,
                   char* pcKey);

    // Inline-Methoden

    char* GetFilePath() {return pcFilePath;}
};

// ******************************************************************


#endif  __TBINIREADER__

Snorky

Frischling

  • »Snorky« ist der Autor dieses Themas

Beiträge: 34

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

3

13.08.2003, 19:22

tbINIReader.cpp

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
/********************************************************************
     _________        __    _____
    /\___  ___\      /\_\  /\  __\
    \/__/\ \__/ _  __\/_/_ \ \ \_\\   ____    _____      __
        \ \ \  /\`´__\ /\ \ \ \  __\ /\ __\_ /\  __\   /´__`\
         \ \ \ \ \ \/  \ \ \ \ \ \_\\\ \\_\ \\ \____\ /\  __/
          \ \_\ \ \_\   \ \_\ \ \____\\ \___\ \ \____\\ \____\
           \/_/  \/_/    \/_/  \/____/ \/__/   \/____/ \/____/

    tbINIReader.cpp
    ===============
    Diese Datei ist Teil der TriBase-Engine.

    Zweck:
    Umgang mit INI-Dateien

    Autor:
    Snorky
    [13.8.2003]

********************************************************************/

#include <TriBase.h>


// ******************************************************************

// Konstruktor der tb2DSprite-Klasse

tbINIReader::tbINIReader()
{
    // Alles zurücksetzen

    ZeroMemory(this, sizeof(tbINIReader));
}

// ******************************************************************

// Destruktor der tb2DSprite-Klasse

tbINIReader::~tbINIReader()
{
}

// ******************************************************************

// Angabe des zu lesenden Ini-Files

tbResult tbINIReader::SetFilePath(char* pcINIFile)
{
    strncpy(pcFilePath, pcINIFile, sizeof(pcFilePath));
    
    return TB_OK;
}

// ******************************************************************

// Liest einen int-Wert aus der INI-Datei

int tbINIReader::ReadINIInt(char* pcSection,
                            char* pcKey)
{
    char acString[256];

    // String lesen

    ReadINIString(pcSection, pcKey, acString, 256);
    if(!strcmp(acString, "[NOT FOUND]")) return 12345678;

    // In int-Wert umwandeln

    return atoi(acString);
}

// ******************************************************************

// Liest einen float-Wert aus der INI-Datei

float tbINIReader::ReadINIFloat(char* pcSection,
                                char* pcKey)
{
    char    acString[256];
    float   fValue;


    // String lesen

    ReadINIString(pcSection, pcKey, acString, 256);
    if(!strcmp(acString, "[NOT FOUND]")) return 12345678.0f;

    // In float-Wert umwandeln

    sscanf(acString, "%f", &fValue);

    return fValue;
}

// ******************************************************************

// Liest einen tbVector3-Wert aus der INI-Datei

tbVector3 tbINIReader::ReadINIVector3(char* pcSection,
                                      char* pcKey)
{
    char        acString[256];
    tbVector3   vValue;


    // String lesen

    ReadINIString(pcSection, pcKey, acString, 256);
    if(!strcmp(acString, "[NOT FOUND]")) return tbVector3(12345678.0f, 12345678.0f, 12345678.0f);

    // Die Vektorkomponenten extrahieren

    sscanf(acString, "%f, %f, %f", &vValue.x, &vValue.y, &vValue.z);

    return vValue;
}

// ******************************************************************

// Liest einen tbColor-Wert aus der INI-Datei

tbColor tbINIReader::ReadINIColor(char* pcSection,
                                  char* pcKey)
{
    char    acString[256];
    tbColor Value;


    // String lesen

    ReadINIString(pcSection, pcKey, acString, 256);
    if(!strcmp(acString, "[NOT FOUND]")) return tbColor(12345678.0f, 12345678.0f, 12345678.0f, 12345678.0f);

    // Die Farbkomponenten extrahieren

    sscanf(acString, "%f, %f, %f, %f", &Value.r, &Value.g, &Value.b, &Value.a);

    return Value;
}

// ******************************************************************

// Liest einen String aus der INI-Datei

tbResult tbINIReader::ReadINIString(char* pcSection,
                                    char* pcKey,
                                    char* pcOut,
                                    int iBufferSize)
{
    // String lesen

    GetPrivateProfileString(pcSection, pcKey, "[NOT FOUND]",
                            pcOut, iBufferSize,
                            pcFilePath);

    return TB_OK;
}

// ******************************************************************

Snorky

Frischling

  • »Snorky« ist der Autor dieses Themas

Beiträge: 34

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

4

13.08.2003, 19:23

tb2DSprite.h

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
/********************************************************************
     _________        __    _____
    /\___  ___\      /\_\  /\  __\
    \/__/\ \__/ _  __\/_/_ \ \ \_\\   ____    _____      __
        \ \ \  /\`´__\ /\ \ \ \  __\ /\ __\_ /\  __\   /´__`\
         \ \ \ \ \ \/  \ \ \ \ \ \_\\\ \\_\ \\ \____\ /\  __/
          \ \_\ \ \_\   \ \_\ \ \____\\ \___\ \ \____\\ \____\
           \/_/  \/_/    \/_/  \/____/ \/__/   \/____/ \/____/

    tb2DSprite.h
    ============
    Diese Datei ist Teil der TriBase-Engine.

    Zweck:
    Umgang mit 2D-Sprites

    Autor:
    Snorky
    [13.8.2003]

********************************************************************/

#ifndef __TB2DSPRITE__
#define __TB2DSPRITE__

#pragma pack(1)


// Struktur für die Informationen über ein Sprite

struct TRIBASE_API tb2DSpriteInfo
{
    float       fTextureWidth;          // Breite der Textur

    float       fTextureHeight;         // Höhe der Textur

    tbVector2   avTopLeftPix[256];      // Linke obere Koordinate jedes Sprites in Pixeln

    tbVector2   avBottomRightPix[256];  // Rechte untere Koordinate jedes Sprites in Pixeln

    tbVector2   avSpriteWidthPix[256];  // Breite und Höhe jedes Sprites in Pixeln

    tbVector2   avTopLeft[256];         // Linke obere Koordinate jedes Sprites

    tbVector2   avBottomRight[256];     // Rechte untere Koordinate jedes Sprites

    tbVector2   avSpriteWidth[256];     // Breite und Höhe jedes Sprites

};

// ******************************************************************

// Vertexformat

#define TB_2DSPRITE_FVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
struct TRIBASE_API tb2DSpriteVertex
{
    tbVector3   vPosition;  // Positionsangabe

    float       fRHW;       // 1/w

    D3DCOLOR    Diffuse;    // Streufarbe

    tbVector2   vTexture;   // Texturkoordinaten

};

// ******************************************************************

// Flags zum Zeichnen von Sprites

#define TB_SF_ALIGN_HLEFT       (0)     // Sprite linksbündig

#define TB_SF_ALIGN_HCENTER     (1)     // Sprite horizontal zentrieren

#define TB_SF_ALIGN_HRIGHT      (2)     // Sprite rechtsbündig

#define TB_SF_ALIGN_VBOTTOM     (4)     // Sprite unten ausrichten

#define TB_SF_ALIGN_VCENTER     (8)     // Sprite vertikal zentrieren

#define TB_SF_ALIGN_VTOP        (16)    // Sprite oben ausrichten

#define TB_SF_RELATIVE          (32)    // Koordinaten sind relativ

#define TB_SF_RELATIVESCALING   (64)    // Skalierung ist relativ

#define TB_SF_ALIGN_CENTER      (128)   // Sprite zentriert


// ******************************************************************

// Klasse für ein Sprite

class TRIBASE_API tb2DSprite
{
private:
    // Variablen

    PDIRECT3DTEXTURE9       m_pTexture;     // Die Textur mit den Sprites

    tb2DSpriteInfo          m_2DSpriteInfo; // Spriteinformationen

    tbEffect*               m_pEffect;      // Effekt


    int                     m_iNumPasses;   // Anzahl der Durchgänge für den Effekt

    DWORD                   m_dwOldFVF;     // Altes Vertexformat (zum Zeitpunkt von Begin)

    tb2DSpriteVertex        aVertex[600];   // Vertexliste der zu zeichnenden Sprites

    DWORD                   dwVertexCursor; // aktuelle Vertexposition in der Liste

    BOOL                    m_bTexturmanager;   // Speichert, ober der Texturmanager verwendet wurde


public:
    // Konstruktor und Destruktor

    tb2DSprite();
    ~tb2DSprite();

    // Methoden

    // Laden aus Dateien

    tbResult    Init(char* pcINIFile,               // INI-Datei-Name

                     char* pcINISection,            // INI-Sektionseintrag

                     char* pcTextureFile = NULL);   // INI-Eintrag nur bei NULL


    tbResult    Begin();                                                                            // Beginnen, Sprites zu zeichnen

    tbResult    End();                                                                              // Beenden, Sprites zu zeichnen

    tbResult    DrawPuffer();                                                                       // Alle Sprites im Puffer sofort malen


    // Liest Spritekoordinaten aus einer INI-Datei und rechnet sie ggf. um

    tbResult ReadINISpriteInfo(tbINIReader* pINIReader,
                               char* pcSection,
                               char* pcKey,
                               tb2DSpriteInfo* s2DSpriteInfo);

    // Sprite zeichnen

    tbResult DrawSprite(tbVector2 vPosition,
                        DWORD dwNumber = 0,
                        const DWORD dwFlags = TB_SF_ALIGN_HLEFT | TB_SF_ALIGN_VTOP,
                        const tbColor& Color1 = tbColor(1.0f),
                        tbVector2 vScaling = tbVector2(1.0f),
                        float fRotating = 0.0f);    // rotate CW in RAD


    // Sprite mit Transformationsmatrix zeichnen

    tbResult DrawTransformedSprite(tbMatrix mTransformation,
                                   DWORD dwNumber = 0,
                                   const DWORD dwFlags = TB_SF_ALIGN_HLEFT | TB_SF_ALIGN_VTOP,
                                   const tbColor& Color1 = tbColor(1.0f));

    // Inline-Methoden

    PDIRECT3DTEXTURE9   GetTexture()    {return m_pTexture;}
    tb2DSpriteInfo      GetInfo()       {return m_2DSpriteInfo;}
    BOOL                GetTMUse()      {return m_bTexturmanager;}
};

// ******************************************************************


#endif __TB2DSPRITE__ 

Snorky

Frischling

  • »Snorky« ist der Autor dieses Themas

Beiträge: 34

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

5

13.08.2003, 19:24

tb2DSprite.cpp

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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
/********************************************************************
     _________        __    _____
    /\___  ___\      /\_\  /\  __\
    \/__/\ \__/ _  __\/_/_ \ \ \_\\   ____    _____      __
        \ \ \  /\`´__\ /\ \ \ \  __\ /\ __\_ /\  __\   /´__`\
         \ \ \ \ \ \/  \ \ \ \ \ \_\\\ \\_\ \\ \____\ /\  __/
          \ \_\ \ \_\   \ \_\ \ \____\\ \___\ \ \____\\ \____\
           \/_/  \/_/    \/_/  \/____/ \/__/   \/____/ \/____/

    tb2DSprite.cpp
    ==============
    Diese Datei ist Teil der TriBase-Engine.

    Zweck:
    Umgang mit 2D-Sprites

    Autor:
    Snorky
    [13.8.2003]

********************************************************************/

#include <TriBase.h>

// ******************************************************************

// Konstruktor der tb2DSprite-Klasse

tb2DSprite::tb2DSprite()
{
    // Alles zurücksetzen

    ZeroMemory(this, sizeof(tb2DSprite));
}

// ******************************************************************

// Destruktor der tb2DSprite-Klasse

tb2DSprite::~tb2DSprite()
{
    // Textur aus dem Effekt nehmen

    m_pEffect->GetEffect()->SetTexture("Texture1", NULL);

    // Textur und Effekt freigeben

    if(m_bTexturmanager)
    {
        m_bTexturmanager = FALSE;
        tbTextureManager::ReleaseTexture(m_pTexture);
    }
    else
    {
        TB_SAFE_RELEASE(m_pTexture);
    }
    TB_SAFE_DELETE(m_pEffect);
}

// ******************************************************************

// Liest Spritekoordinaten aus einer INI-Datei und rechnet sie ggf. um

tbResult tb2DSprite::ReadINISpriteInfo(tbINIReader* pINIReader,
                                       char* pcSection,
                                       char* pcKey,
                                       tb2DSpriteInfo* s2DSpriteInfo)
{
    char        acKey[256];
    char        acString[256];


    // Werte-Array durchgehen

    for(int i = 0; i < 256; i++) {
        // String lesen

        sprintf(acKey, "%s%d", pcKey, i);
        pINIReader->ReadINIString(pcSection, acKey, acString, 256);
        if(!strcmp(acString, "[NOT FOUND]")) return TB_NOT_FOUND;

        // Die Vektorkomponenten extrahieren

        int x1,x2,y1,y2;
        sscanf(acString, "%d, %d, %d, %d", &x1, &y1, &x2, &y2);
        s2DSpriteInfo->avTopLeftPix[i].x = (float)x1;
        s2DSpriteInfo->avTopLeftPix[i].y = (float)y1;
        if(x2 % 2 == 1) s2DSpriteInfo->avSpriteWidthPix[i].x = (float)(x2);
        else s2DSpriteInfo->avSpriteWidthPix[i].x = (float)(x2-1);
        if(y2 % 2 == 1) s2DSpriteInfo->avSpriteWidthPix[i].y = (float)(y2);
        else s2DSpriteInfo->avSpriteWidthPix[i].y = (float)(y2-1);
        s2DSpriteInfo->avTopLeft[i].x = ((float)(x1)) / (s2DSpriteInfo->fTextureWidth-1);
        s2DSpriteInfo->avTopLeft[i].y = ((float)(y1)) / (s2DSpriteInfo->fTextureHeight-1);
        s2DSpriteInfo->avSpriteWidth[i].x = ((float)(x2)) / (s2DSpriteInfo->fTextureWidth-1);
        s2DSpriteInfo->avSpriteWidth[i].y = ((float)(y2)) / (s2DSpriteInfo->fTextureHeight-1);

        // untere rechte Ecke berechnen

        s2DSpriteInfo->avBottomRight[i] = s2DSpriteInfo->avTopLeft[i] + s2DSpriteInfo->avSpriteWidth[i];
        s2DSpriteInfo->avBottomRightPix[i] = s2DSpriteInfo->avTopLeftPix[i] + s2DSpriteInfo->avSpriteWidthPix[i];
    }

    return TB_OK;
}

// ******************************************************************

// Initialisierung aus virtuellen Dateien

tbResult tb2DSprite::Init(char* pcINIFile,
                          char* pcINISection,
                          char* pcTextureFile)      // = NULL

{
    HRESULT     hResult;
    tbResult    tbRes;

    // Parameter prüfen und sicherstellen, dass tbDirect3D initialisiert wurde

    if(pcINIFile == NULL)               TB_ERROR_NULL_POINTER("pcINIFile", TB_ERROR);
    if(pcINISection == NULL)            TB_ERROR_NULL_POINTER("pcINISection", TB_ERROR);
    if(!tbDirect3D::IsInitialized())    TB_ERROR("Es muss zuerst eine tbDirect3D-Klasseninstanz erstellt werden!", TB_ERROR);

    
    // Informationsdatei vorbereiten

    tbINIReader* pINIReader;
    pINIReader = new tbINIReader;   if(pINIReader == NULL) TB_ERROR_OUT_OF_MEMORY(TB_ERROR);
    pINIReader->SetFilePath(pcINIFile);

    // ColorKey laden

    tbColor ColorKey = pINIReader->ReadINIColor(pcINISection, "ColorKey");
    if(ColorKey == tbVector3(12345678.0f, 12345678.0f, 12345678.0f)) ColorKey = tbColor(0.0f);
    

    // Wenn kein Parameter übergeben nach INI-Eintrag suchen

    char acTextur[256];
    if(pcTextureFile == NULL)
    {
        // Texturname aus INI laden wenn möglich

        pINIReader->ReadINIString(pcINISection, "Texture", acTextur, 256);
    
        // Kein INI-Eintrag gefunden?

        if(!strcmp(acTextur, "[NOT FOUND]"))
        {
            TB_ERROR("Fehler beim Laden der Sprite-Textur, kein INI-Eintrag gefunden!", TB_ERROR);
        }
    }
    else
    {
        strncpy(acTextur, pcTextureFile, 256);
    }

    // Texturmanager benutzen, wenn er initialisiert ist

    if(tbTextureManager::IsInitialized())
    {
        // Texturmanager benutzen merken

        m_bTexturmanager = TRUE;

        m_pTexture = tbTextureManager::GetTexture(acTextur, 
                        TRUE, D3DX_DEFAULT, D3DX_DEFAULT, 
                        1, D3DFMT_UNKNOWN, 0, D3DPOOL_MANAGED, 
                        D3DX_DEFAULT, D3DX_DEFAULT, ColorKey);
        // Fehler?

        if(m_pTexture == NULL) TB_ERROR("Fehler beim Laden der Textur mit dem Texturmanager!",TB_ERROR);

        // Bilddimensionen speichern

        int iTextureIndex = tbTextureManager::GetTextureIndex(m_pTexture);
        tbTextureListEntry* pTextureList = tbTextureManager::GetTextureList();
        m_2DSpriteInfo.fTextureHeight = (float)pTextureList[iTextureIndex].iHeight;
        m_2DSpriteInfo.fTextureWidth = (float)pTextureList[iTextureIndex].iWidth;
    }
    else
    {
        // Texturmanager nicht benutzen merken

        m_bTexturmanager = FALSE;

        tbVFile*    pVFile;

        // Virtuelle Dateien erstellen

        pVFile = new tbVFile;   if(pVFile == NULL) TB_ERROR_OUT_OF_MEMORY(TB_ERROR);

        // Aus Datei laden

        if(pVFile->Init(acTextur)) TB_ERROR("Fehler beim Erstellen der virtuellen Datei!", TB_ERROR);

        // Textur laden

        D3DXIMAGE_INFO dinfo;
        ZeroMemory(&dinfo, sizeof(dinfo));
        if(FAILED(hResult = D3DXCreateTextureFromFileInMemoryEx(tbDirect3D::GetDevice(),
                                                                (BYTE*)(pVFile->GetBuffer()) + pVFile->GetCursor(),
                                                                pVFile->GetSize() - pVFile->GetCursor(),
                                                                D3DX_DEFAULT, D3DX_DEFAULT, 1, 0,
                                                                D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
                                                                D3DX_DEFAULT, D3DX_DEFAULT,
                                                                ColorKey, &dinfo, NULL, &m_pTexture)))
        {
            // Fehler!

            TB_ERROR_DIRECTX("D3DXCreateTextureFromFileInMemoryEx", hResult, TB_ERROR);
        }
        // Bilddimensionen speichern

        m_2DSpriteInfo.fTextureHeight = (float)dinfo.Height;
        m_2DSpriteInfo.fTextureWidth = (float)dinfo.Width;

        // Die virtuellen Dateien wieder freigeben

        TB_SAFE_DELETE(pVFile);
    }


    // Sprite-Informationen laden

    ReadINISpriteInfo(pINIReader,
                      pcINISection, 
                      "Sprite", 
                      &m_2DSpriteInfo);


    // Effektname aus INI laden

    char acEffect[256];
    pINIReader->ReadINIString(pcINISection, "Effect", acEffect, 256);
    if(!strcmp(acEffect, "[NOT FOUND]")) TB_ERROR("Fehler beim Laden des Sprite-Effekts!", TB_ERROR);
    // Effekt laden

    m_pEffect = new tbEffect; if(m_pEffect == NULL) TB_ERROR_OUT_OF_MEMORY(TB_ERROR);
    if(TB_OK != (tbRes = m_pEffect->Init(acEffect))) TB_ERROR("Fehler beim Erstellen des Sprite-Effekts!", TB_ERROR);
    // Effekt setzen

    if(TB_OK != m_pEffect->SetTechnique())  TB_ERROR("Fehler beim Setzen des Sprite-Effekts!", TB_ERROR);

    // Textur setzen

    if(FAILED(hResult = m_pEffect->GetEffect()->SetTexture("Texture1", m_pTexture)))
    {
        // Fehler!

        TB_ERROR_DIRECTX("SetTexture", hResult, TB_ERROR);
    }


    // INIReader wieder freigeben

    TB_SAFE_DELETE(pINIReader);

    return TB_OK;
}

// ******************************************************************

// Beginnt mit den Sprites

tbResult tb2DSprite::Begin()
{
    // Aktuellen Status speichern

    m_dwOldFVF = tbDirect3D::GetFVF();

    // Neues Vertexformat setzen

    tbDirect3D::SetFVF(TB_2DSPRITE_FVF);

    // Mit dem Effekt beginnen

    m_iNumPasses = m_pEffect->Begin();

    // Vertexcursor setzen

    dwVertexCursor = 0;

    return TB_OK;
}

// ******************************************************************

// Beenden

tbResult tb2DSprite::End()
{
    // Wenn noch was im Puffer steht, dann wird jetzt gezeichnet.

    if(dwVertexCursor > 0)
    {
        DrawPuffer();
    }

    // Effekt beenden

    m_pEffect->End();

    // Wiederherstellen des alten Status

    tbDirect3D::SetFVF(m_dwOldFVF);

    return TB_OK;
}

// ******************************************************************

// Alle Sprites im Puffer sofort malen

tbResult tb2DSprite::DrawPuffer()
{
    // Jeden Durchgang des Effekts zeichnen

    for(int iPass = 0; iPass < m_iNumPasses; iPass++)
    {
        m_pEffect->Pass(iPass);

        tbDirect3D::GetDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST,
                                                 dwVertexCursor / 3,
                                                 aVertex,
                                                 sizeof(tb2DSpriteVertex));
    }

    // Vertexcursor zurücksetzen

    dwVertexCursor = 0;

    return TB_OK;
}

// ******************************************************************

// Diese Methode zeichnet ein Sprite.

tbResult tb2DSprite::DrawSprite(tbVector2 vPosition,
                                DWORD dwNumber,             // = 0

                                const DWORD dwFlags,        // = TB_SF_ALIGN_HLEFT | TB_SF_ALIGN_VTOP

                                const tbColor& Color1,      // = tbColor(1.0f)

                                tbVector2 vScaling,         // = tbVector2(1.0f)

                                float fRotating)            // = 0.0f

{
    // Wenn rotiert werden soll muss transformated Sprite her

    if(fRotating != 0.0f)
    {
        tbMatrix    mTransformation;

        mTransformation = tbMatrixScaling(tbVector3(vScaling.x, vScaling.y, 1.0f));
        mTransformation *= tbMatrixRotationZ(fRotating);
        mTransformation *= tbMatrixTranslation(tbVector3(vPosition.x, vPosition.y, 0.0f));
        
        return DrawTransformedSprite(mTransformation, dwNumber, dwFlags, Color1);
    }

    // Relative Koordinaten in absolute umrechnen

    if(dwFlags & TB_SF_RELATIVE)
    {
        vPosition.x *= tbDirect3D::GetScreenSize().x;
        vPosition.y *= tbDirect3D::GetScreenSize().y;
    }

    // Relative Skalierung in absolute umrechnen

    if(dwFlags & TB_SF_RELATIVESCALING)
    {
        vScaling.x *= tbDirect3D::GetScreenSize().x / 640.0f;
        vScaling.y *= tbDirect3D::GetScreenSize().y / 480.0f;
    }


    tbVector2 vCursor(vPosition);
    // Breite des Sprites abfragen

    float fSpriteWidth = m_2DSpriteInfo.avSpriteWidthPix[dwNumber].x * vScaling.x;
    float fSpriteHight = m_2DSpriteInfo.avSpriteWidthPix[dwNumber].y * vScaling.y;


    // Cursor auf die horizontale Startposition setzen

    if((dwFlags & TB_SF_ALIGN_HCENTER) || (dwFlags & TB_SF_ALIGN_CENTER))
    {
        // Zentrieren

        vCursor.x -= 0.5f * (fSpriteWidth);
    }
    else if(dwFlags & TB_SF_ALIGN_HRIGHT)
    {
        // Rechtsbündig

        vCursor.x -= fSpriteWidth-1;
    }
    else
    {
        // Linksbündig

    }


    // Cursor auf die vertikale Startposition setzen

    if((dwFlags & TB_SF_ALIGN_VCENTER) || (dwFlags & TB_SF_ALIGN_CENTER))
    {
        // vertikal zentrieren

        vCursor.y -= 0.5f * fSpriteHight;
    }

    else if(dwFlags & TB_SF_ALIGN_VBOTTOM)
    {
        // unten ausrichten

        vCursor.y -= fSpriteHight-1;
    }
    else
    {
        // oben ausrichten

    }


    // Sechs Vertizes für das Sprite hinzufügen.

    // Dazu verwenden wir Dreieckslisten - jeweils sechs Vertizes

    // beschreiben ein Viereck.


    // Erster Vertex: links oben

    aVertex[dwVertexCursor].vPosition = tbVector3(vCursor.x, vCursor.y, 0.0f);
    aVertex[dwVertexCursor].fRHW = 1.0f;
    aVertex[dwVertexCursor].Diffuse = Color1;
    aVertex[dwVertexCursor].vTexture = m_2DSpriteInfo.avTopLeft[dwNumber];

    // Zweiter Vertex: rechts oben

    aVertex[dwVertexCursor + 1].vPosition = tbVector3(vCursor.x + fSpriteWidth, vCursor.y, 0.0f);
    aVertex[dwVertexCursor + 1].fRHW = 1.0f;
    aVertex[dwVertexCursor + 1].Diffuse = Color1;
    aVertex[dwVertexCursor + 1].vTexture.x = m_2DSpriteInfo.avBottomRight[dwNumber].x;
    aVertex[dwVertexCursor + 1].vTexture.y = m_2DSpriteInfo.avTopLeft[dwNumber].y;

    // Dritter Vertex: rechts unten

    aVertex[dwVertexCursor + 2].vPosition = tbVector3(vCursor.x + fSpriteWidth, vCursor.y + fSpriteHight, 0.0f);
    aVertex[dwVertexCursor + 2].fRHW = 1.0f;
    aVertex[dwVertexCursor + 2].Diffuse = Color1;
    aVertex[dwVertexCursor + 2].vTexture = m_2DSpriteInfo.avBottomRight[dwNumber];

    // Vierter Vertex = erster Vertex

    aVertex[dwVertexCursor + 3] = aVertex[dwVertexCursor];

    // Fünfter Vertex = dritter Vertex

    aVertex[dwVertexCursor + 4] = aVertex[dwVertexCursor + 2];


    // Sechster Vertex: links unten

    aVertex[dwVertexCursor + 5].vPosition = tbVector3(vCursor.x, vCursor.y + fSpriteHight, 0.0f);
    aVertex[dwVertexCursor + 5].fRHW = 1.0f;
    aVertex[dwVertexCursor + 5].Diffuse = Color1;
    aVertex[dwVertexCursor + 5].vTexture.x = m_2DSpriteInfo.avTopLeft[dwNumber].x;
    aVertex[dwVertexCursor + 5].vTexture.y = m_2DSpriteInfo.avBottomRight[dwNumber].x;

    // Vertexcursor aktualisieren

    dwVertexCursor += 6;


    // Wenn das Vertex-Array voll ist, dann wird jetzt gezeichnet.

    if(dwVertexCursor >= 600)
    {
        DrawPuffer();
    }

    return TB_OK;
}

// ******************************************************************

// Sprite mit Transformationsmatrix zeichnen

tbResult tb2DSprite::DrawTransformedSprite(tbMatrix mTransformation,
                                           DWORD dwNumber,          // = 0

                                           const DWORD dwFlags,     // = TB_SF_ALIGN_HLEFT | TB_SF_ALIGN_VTOP

                                           const tbColor& Color1)   // = tbColor(1.0f)

{
    // Relative Koordinaten in absolute umrechnen

    if(dwFlags & TB_SF_RELATIVE)
    {
        mTransformation.m41 *= tbDirect3D::GetScreenSize().x;
        mTransformation.m42 *= tbDirect3D::GetScreenSize().y;
    }

    // Relative Größe in absolute umrechnen

    if(dwFlags & TB_SF_RELATIVESCALING)
    {
        mTransformation.m11 *= tbDirect3D::GetScreenSize().x / 640.0f;
        mTransformation.m22 *= tbDirect3D::GetScreenSize().y / 480.0f;
    }

    tbVector2 vCursor(0.0f);
    // Breite des Sprites abfragen

    float fSpriteWidth = m_2DSpriteInfo.avSpriteWidthPix[dwNumber].x;
    float fSpriteHight = m_2DSpriteInfo.avSpriteWidthPix[dwNumber].y;

    // Cursor auf die horizontale Startposition setzen

    if((dwFlags & TB_SF_ALIGN_HCENTER) || (dwFlags & TB_SF_ALIGN_CENTER))
    {
        // Zentrieren

        vCursor.x = -0.5f * (fSpriteWidth);
    }
    else if(dwFlags & TB_SF_ALIGN_HRIGHT)
    {
        // Rechtsbündig

        vCursor.x = -(fSpriteWidth-1);
    }
    else
    {
        // Linksbündig

    }

    // Cursor auf die vertikale Startposition setzen

    if((dwFlags & TB_SF_ALIGN_VCENTER) || (dwFlags & TB_SF_ALIGN_CENTER))
    {
        // vertikal zentrieren

        vCursor.y = -0.5f * (fSpriteHight);
    }
    else if(dwFlags & TB_SF_ALIGN_VTOP)
    {
        // oben ausrichten

        vCursor.y = -(fSpriteHight-1);
    }
    else
    {
        // unten ausrichten

    }


    // Sechs Vertizes für das Sprite hinzufügen.

    // Dazu verwenden wir Dreieckslisten - jeweils sechs Vertizes

    // beschreiben ein Viereck.


    // Erster Vertex: links oben

    aVertex[dwVertexCursor].vPosition = tbVector3(vCursor.x, vCursor.y, 0.0f);
    aVertex[dwVertexCursor].vPosition = tbVector3TransformCoords(aVertex[dwVertexCursor].vPosition, mTransformation);
    aVertex[dwVertexCursor].fRHW = 1.0f;
    aVertex[dwVertexCursor].Diffuse = Color1;
    aVertex[dwVertexCursor].vTexture = m_2DSpriteInfo.avTopLeft[dwNumber];

    // Zweiter Vertex: rechts oben

    aVertex[dwVertexCursor + 1].vPosition = tbVector3(vCursor.x + fSpriteWidth, vCursor.y, 0.0f);
    aVertex[dwVertexCursor + 1].vPosition = tbVector3TransformCoords(aVertex[dwVertexCursor + 1].vPosition, mTransformation);
    aVertex[dwVertexCursor + 1].fRHW = 1.0f;
    aVertex[dwVertexCursor + 1].Diffuse = Color1;
    aVertex[dwVertexCursor + 1].vTexture.x = m_2DSpriteInfo.avBottomRight[dwNumber].x;
    aVertex[dwVertexCursor + 1].vTexture.y = m_2DSpriteInfo.avTopLeft[dwNumber].y;

    // Dritter Vertex: rechts unten

    aVertex[dwVertexCursor + 2].vPosition = tbVector3(vCursor.x + fSpriteWidth, vCursor.y + fSpriteHight, 0.0f);
    aVertex[dwVertexCursor + 2].vPosition = tbVector3TransformCoords(aVertex[dwVertexCursor + 2].vPosition, mTransformation);
    aVertex[dwVertexCursor + 2].fRHW = 1.0f;
    aVertex[dwVertexCursor + 2].Diffuse = Color1;
    aVertex[dwVertexCursor + 2].vTexture = m_2DSpriteInfo.avBottomRight[dwNumber];

    // Vierter Vertex = erster Vertex

    aVertex[dwVertexCursor + 3] = aVertex[dwVertexCursor];

    // Fünfter Vertex = dritter Vertex

    aVertex[dwVertexCursor + 4] = aVertex[dwVertexCursor + 2];

    // Sechster Vertex: links unten

    aVertex[dwVertexCursor + 5].vPosition = tbVector3(vCursor.x, vCursor.y + fSpriteHight, 0.0f);
    aVertex[dwVertexCursor + 5].vPosition = tbVector3TransformCoords(aVertex[dwVertexCursor + 5].vPosition, mTransformation);
    aVertex[dwVertexCursor + 5].fRHW = 1.0f;
    aVertex[dwVertexCursor + 5].Diffuse = Color1;
    aVertex[dwVertexCursor + 5].vTexture.x = m_2DSpriteInfo.avTopLeft[dwNumber].x;
    aVertex[dwVertexCursor + 5].vTexture.y = m_2DSpriteInfo.avBottomRight[dwNumber].x;

    // Vertexcursor aktualisieren

    dwVertexCursor += 6;

    // Wenn das Vertex-Array voll ist, dann wird jetzt gezeichnet.

    if(dwVertexCursor >= 600)
    {
        DrawPuffer();
    }

    return TB_OK;
}

// ****************************************************************** 

Snorky

Frischling

  • »Snorky« ist der Autor dieses Themas

Beiträge: 34

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

6

13.08.2003, 19:24

tb2DVolumeSprite.h

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
/********************************************************************
     _________        __    _____
    /\___  ___\      /\_\  /\  __\
    \/__/\ \__/ _  __\/_/_ \ \ \_\\   ____    _____      __
        \ \ \  /\`´__\ /\ \ \ \  __\ /\ __\_ /\  __\   /´__`\
         \ \ \ \ \ \/  \ \ \ \ \ \_\\\ \\_\ \\ \____\ /\  __/
          \ \_\ \ \_\   \ \_\ \ \____\\ \___\ \ \____\\ \____\
           \/_/  \/_/    \/_/  \/____/ \/__/   \/____/ \/____/

    tb2DVolumeSprite.h
    ==================
    Diese Datei ist Teil der TriBase-Engine.

    Zweck:
    Umgang mit 2D-Volumen-Sprites

    Autor:
    Snorky
    [13.8.2003]

********************************************************************/

#ifndef __TB2DVOLUMESPRITE__
#define __TB2DVOLUMESPRITE__

#pragma pack(1)


// Struktur für die Informationen über ein Volumensprite

struct TRIBASE_API tb2DVolumeSpriteInfo
{
    float       fTextureWidth;          // Breite der Textur

    float       fTextureHeight;         // Höhe der Textur

    float       fTextureDepth;          // Tiefe der Textur

    tbVector2   avTopLeftPix[256];      // Linke obere Koordinate jedes Sprites in Pixeln

    tbVector2   avBottomRightPix[256];  // Rechte untere Koordinate jedes Sprites in Pixeln

    tbVector2   avSpriteWidthPix[256];  // Breite und Höhe jedes Sprites in Pixeln

    tbVector2   avTopLeft[256];         // Linke obere Koordinate jedes Sprites

    tbVector2   avBottomRight[256];     // Rechte untere Koordinate jedes Sprites

    tbVector2   avSpriteWidth[256];     // Breite und Höhe jedes Sprites

};

// ******************************************************************

// Vertexformat

#define TB_2DVOLUMESPRITE_FVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0))
struct TRIBASE_API tb2DVolumeSpriteVertex
{
    tbVector3   vPosition;  // Positionsangabe

    float       fRHW;       // 1/w

    D3DCOLOR    Diffuse;    // Streufarbe

    tbVector3   vTexture;   // Texturkoordinaten

};

// ******************************************************************

// Flags zum Zeichnen von Volumensprites

#define TB_SVF_ALIGN_HLEFT      (0)     // Sprite linksbündig

#define TB_SVF_ALIGN_HCENTER    (1)     // Sprite horizontal zentrieren

#define TB_SVF_ALIGN_HRIGHT     (2)     // Sprite rechtsbündig

#define TB_SVF_ALIGN_VBOTTOM    (4)     // Sprite unten ausrichten

#define TB_SVF_ALIGN_VCENTER    (8)     // Sprite vertikal zentrieren

#define TB_SVF_ALIGN_VTOP       (16)    // Sprite oben ausrichten

#define TB_SVF_RELATIVE         (32)    // Koordinaten sind relativ

#define TB_SVF_RELATIVESCALING  (64)    // Skalierung ist relativ

#define TB_SVF_ALIGN_CENTER     (128)   // Sprite zentriert

#define TB_SVF_DEPTH_RELATIVE   (256)   // Texturtiefe ist relativ (0..1)

#define TB_SVF_DEPTH_ABSOLUTE   (512)   // Texturtiefe ist absolut (ganze Zahlen = Texturtiefennummer, Nachkomma = Alphawert)


// ******************************************************************

// Klasse für ein Volumensprite

class TRIBASE_API tb2DVolumeSprite
{
private:
    // Variablen

    PDIRECT3DBASETEXTURE9   m_pTexture;     // Die Textur mit den Sprites

    tb2DVolumeSpriteInfo    m_2DSpriteInfo; // Spriteinformationen

    tbEffect*               m_pEffect;      // Effekt

    int                     m_iNumPasses;   // Anzahl der Durchgänge für den Effekt

    DWORD                   m_dwOldFVF;     // Altes Vertexformat (zum Zeitpunkt von Begin)

    tb2DVolumeSpriteVertex  aVertex[600];   // Vertexliste der zu zeichnenden Sprites

    DWORD                   dwVertexCursor; // aktuelle Vertexposition in der Liste

    BOOL                    m_bTexturmanager;   // Speichert, ober der Texturmanager verwendet wurde

    BOOL                    m_bVolumeUse;   // Speichert, ob Volumentexturen unterstützt werden oder nicht

    
public:
    // Konstruktor und Destruktor

    tb2DVolumeSprite();
    ~tb2DVolumeSprite();

    // Methoden

    // Laden aus Dateien

    tbResult    Init(char* pcINIFile,               // INI-Datei-Name

                     char* pcINISection,            // INI-Sektionseintrag

                     char* pcTextureFile = NULL);   // INI-Eintrag nur bei NULL


    tbResult    Begin();                                                                            // Beginnen, Sprites zu zeichnen

    tbResult    End();                                                                              // Beenden, Sprites zu zeichnen

    tbResult    DrawPuffer();                                                                       // Alle Sprites im Puffer sofort malen


    // Liest Spritekoordinaten aus einer INI-Datei und rechnet sie ggf. um

    tbResult ReadINIVolumeSpriteInfo(tbINIReader* pINIReader,
                                    char* pcSection,
                                    char* pcKey,
                                    tb2DVolumeSpriteInfo* s2DSpriteInfo);

    // Sprite zeichnen

    tbResult DrawSprite(tbVector2 vPosition,
                        float fDepth = 0.0f,
                        DWORD dwNumber = 0,
                        const DWORD dwFlags = TB_SVF_ALIGN_HLEFT | TB_SVF_ALIGN_VTOP | TB_SVF_DEPTH_ABSOLUTE,
                        const tbColor& Color1 = tbColor(1.0f),
                        tbVector2 vScaling = tbVector2(1.0f),
                        float fRotating = 0.0f);    // rotate CW in RAD


    // Sprite mit Transformationsmatrix zeichnen

    tbResult DrawTransformedSprite(tbMatrix mTransformation,
                                   float fDepth = 0.0f,
                                   DWORD dwNumber = 0,
                                   const DWORD dwFlags = TB_SVF_ALIGN_HLEFT | TB_SVF_ALIGN_VTOP | TB_SVF_DEPTH_ABSOLUTE,
                                   const tbColor& Color1 = tbColor(1.0f));

    // Inline-Methoden

    PDIRECT3DBASETEXTURE9   GetTexture()    {return m_pTexture;}
    tb2DVolumeSpriteInfo    GetInfo()       {return m_2DSpriteInfo;}
    BOOL                    GetTMUse()      {return m_bTexturmanager;}
    BOOL                    GetVolumeUse()  {return m_bVolumeUse;}
};

// ******************************************************************


#endif __TB2DVOLUMESPRITE__

Snorky

Frischling

  • »Snorky« ist der Autor dieses Themas

Beiträge: 34

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

7

13.08.2003, 19:25

tb2DVolumeSprite.cpp

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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
/********************************************************************
     _________        __    _____
    /\___  ___\      /\_\  /\  __\
    \/__/\ \__/ _  __\/_/_ \ \ \_\\   ____    _____      __
        \ \ \  /\`´__\ /\ \ \ \  __\ /\ __\_ /\  __\   /´__`\
         \ \ \ \ \ \/  \ \ \ \ \ \_\\\ \\_\ \\ \____\ /\  __/
          \ \_\ \ \_\   \ \_\ \ \____\\ \___\ \ \____\\ \____\
           \/_/  \/_/    \/_/  \/____/ \/__/   \/____/ \/____/

    tb2DVolumeSprite.cpp
    ====================
    Diese Datei ist Teil der TriBase-Engine.

    Zweck:
    Umgang mit 2D-Volumen-Sprites

    Autor:
    Snorky
    [13.8.2003]

********************************************************************/

#include <TriBase.h>

// ******************************************************************

// Konstruktor der tb2DVolumeSprite-Klasse

tb2DVolumeSprite::tb2DVolumeSprite()
{
    // Alles zurücksetzen

    ZeroMemory(this, sizeof(tb2DVolumeSprite));
}

// ******************************************************************

// Destruktor der tb2DVolumeSprite-Klasse

tb2DVolumeSprite::~tb2DVolumeSprite()
{
    // Textur aus dem Effekt nehmen

    m_pEffect->GetEffect()->SetTexture("Texture1", NULL);

    // Textur freigeben

    if(m_bTexturmanager)
    {
        tbTextureManager::ReleaseTexture(m_pTexture);
    }
    else
    {
        TB_SAFE_RELEASE(m_pTexture);
    }

    // Effekt freigeben

    TB_SAFE_DELETE(m_pEffect);
}

// ******************************************************************

// Liest Spritekoordinaten aus einer INI-Datei und rechnet sie ggf. um

tbResult tb2DVolumeSprite::ReadINIVolumeSpriteInfo(tbINIReader* pINIReader,
                                                    char* pcSection,
                                                    char* pcKey,
                                                    tb2DVolumeSpriteInfo* s2DSpriteInfo)
{
    char        acKey[256];
    char        acString[256];


    // Werte-Array durchgehen

    for(int i = 0; i < 256; i++) {
        // String lesen

        sprintf(acKey, "%s%d", pcKey, i);
        pINIReader->ReadINIString(pcSection, acKey, acString, 256);
        if(!strcmp(acString, "[NOT FOUND]")) return TB_NOT_FOUND;

        // Die Vektorkomponenten extrahieren

        int x1,x2,y1,y2;
        sscanf(acString, "%d, %d, %d, %d", &x1, &y1, &x2, &y2);
        s2DSpriteInfo->avTopLeftPix[i].x = (float)x1;
        s2DSpriteInfo->avTopLeftPix[i].y = (float)y1;
        if(x2 % 2 == 1) s2DSpriteInfo->avSpriteWidthPix[i].x = (float)(x2);
        else s2DSpriteInfo->avSpriteWidthPix[i].x = (float)(x2-1);
        if(y2 % 2 == 1) s2DSpriteInfo->avSpriteWidthPix[i].y = (float)(y2);
        else s2DSpriteInfo->avSpriteWidthPix[i].y = (float)(y2-1);
        s2DSpriteInfo->avTopLeft[i].x = ((float)(x1)) / (s2DSpriteInfo->fTextureWidth-1);
        s2DSpriteInfo->avTopLeft[i].y = ((float)(y1)) / (s2DSpriteInfo->fTextureHeight-1);
        s2DSpriteInfo->avSpriteWidth[i].x = ((float)(x2)) / (s2DSpriteInfo->fTextureWidth-1);
        s2DSpriteInfo->avSpriteWidth[i].y = ((float)(y2)) / (s2DSpriteInfo->fTextureHeight-1);

        // untere rechte Ecke berechnen

        s2DSpriteInfo->avBottomRight[i] = s2DSpriteInfo->avTopLeft[i] + s2DSpriteInfo->avSpriteWidth[i];
        s2DSpriteInfo->avBottomRightPix[i] = s2DSpriteInfo->avTopLeftPix[i] + s2DSpriteInfo->avSpriteWidthPix[i];
    }

    return TB_OK;
}

// ******************************************************************

// Initialisierung aus virtuellen Dateien

tbResult tb2DVolumeSprite::Init(char* pcINIFile,
                                char* pcINISection,
                                char* pcTextureFile)        // = NULL

{
    HRESULT     hResult;
    tbResult    tbRes;

    // Parameter prüfen und sicherstellen, dass tbDirect3D initialisiert wurde

    if(pcINIFile == NULL)               TB_ERROR_NULL_POINTER("pcINIFile", TB_ERROR);
    if(pcINISection == NULL)            TB_ERROR_NULL_POINTER("pcINISection", TB_ERROR);
    if(!tbDirect3D::IsInitialized())    TB_ERROR("Es muss zuerst eine tbDirect3D-Klasseninstanz erstellt werden!", TB_ERROR);

    
    // Informationsdatei vorbereiten

    tbINIReader* pINIReader;
    pINIReader = new tbINIReader;   if(pINIReader == NULL) TB_ERROR_OUT_OF_MEMORY(TB_ERROR);
    pINIReader->SetFilePath(pcINIFile);

    // ColorKey laden

    tbColor ColorKey = pINIReader->ReadINIColor(pcINISection, "ColorKey");
    if(ColorKey == tbVector3(12345678.0f, 12345678.0f, 12345678.0f)) ColorKey = tbColor(0.0f);
    

    // Wenn kein Parameter übergeben nach INI-Eintrag suchen

    char acTextur[256];
    if(pcTextureFile == NULL)
    {
        // Texturname aus INI laden wenn möglich

        pINIReader->ReadINIString(pcINISection, "Texture", acTextur, 256);
    
        // Kein INI-Eintrag gefunden?

        if(!strcmp(acTextur, "[NOT FOUND]"))
        {
            TB_ERROR("Fehler beim Laden der Sprite-Textur, kein INI-Eintrag gefunden!", TB_ERROR);
        }
    }
    else
    {
        strncpy(acTextur, pcTextureFile, 256);
    }

    // Texturmanager benutzen, wenn er initialisiert ist

    if(false&&tbTextureManager::IsInitialized())
    {
        // Texturmanager benutzen merken

        m_bTexturmanager = TRUE;

        m_pTexture = tbTextureManager::GetVolumeTexture(acTextur, 
                        TRUE, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
                        1, D3DFMT_UNKNOWN, 0, D3DPOOL_MANAGED, 
                        D3DX_DEFAULT, D3DX_DEFAULT, ColorKey);

        // werden keine Volumentexturen unterstützt?

        if(m_pTexture == NULL)
        {
            m_bVolumeUse = FALSE;
            TB_WARNING("Es werden keine Volumentexturen unterstützt!");

            // Alternativ-Texturname aus INI laden wenn möglich

            pINIReader->ReadINIString(pcINISection, "TextureAlt", acTextur, 256);
            // Kein INI-Eintrag gefunden?

            if(!strcmp(acTextur, "[NOT FOUND]")) TB_ERROR("Fehler beim Laden der alternativen Volumen-Textur, kein INI-Eintrag gefunden!", TB_ERROR);

            // Alternativbild laden

            m_pTexture = tbTextureManager::GetTexture(acTextur, 
                        TRUE, D3DX_DEFAULT, D3DX_DEFAULT,
                        1, D3DFMT_UNKNOWN, 0, D3DPOOL_MANAGED, 
                        D3DX_DEFAULT, D3DX_DEFAULT, ColorKey);
        
            // Fehler?

            if(m_pTexture == NULL) TB_ERROR("Fehler beim Laden der alternativen Textur mit dem Texturmanager!",TB_ERROR);
        }
        else
        {
            // volle Volumentexturunterstützung

            m_bVolumeUse = TRUE;
        }

        // Bilddimensionen speichern

        int iTextureIndex = tbTextureManager::GetTextureIndex(m_pTexture);
        tbTextureListEntry* pTextureList = tbTextureManager::GetTextureList();
        m_2DSpriteInfo.fTextureHeight = (float)pTextureList[iTextureIndex].iHeight;
        m_2DSpriteInfo.fTextureWidth = (float)pTextureList[iTextureIndex].iWidth;
        m_2DSpriteInfo.fTextureDepth = (float)pTextureList[iTextureIndex].iDepth;
    }
    else
    {

        // Texturmanager nicht benutzen merken

        m_bTexturmanager = FALSE;

        tbVFile*    pVFile;
        D3DXIMAGE_INFO dinfo;
        ZeroMemory(&dinfo, sizeof(dinfo));

        // Virtuelle Dateien erstellen

        pVFile = new tbVFile;
        if(pVFile == NULL) TB_ERROR_OUT_OF_MEMORY(TB_ERROR);

        // Aus Datei laden

        if(pVFile->Init(acTextur))
        {
            goto Label_LoadAlternativeVolumeTextur;
        }

        // Textur laden

        hResult = D3DXCreateVolumeTextureFromFileInMemoryEx(tbDirect3D::GetDevice(),
                    (BYTE*)(pVFile->GetBuffer()) + pVFile->GetCursor(),
                    pVFile->GetSize() - pVFile->GetCursor(),
                    D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
                    1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
                    D3DX_DEFAULT, D3DX_DEFAULT,
                    ColorKey, &dinfo, NULL, 
                    (PDIRECT3DVOLUMETEXTURE9*)(&m_pTexture));
        if(FAILED(hResult) || m_pTexture == NULL)
        {
Label_LoadAlternativeVolumeTextur:
            TB_WARNING("Es werden keine Volumentexturen unterstützt!");
            // Alternativ-Texturname aus INI laden wenn möglich

            pINIReader->ReadINIString(pcINISection, "TextureAlt", acTextur, 256);
            // Kein INI-Eintrag gefunden?

            if(!strcmp(acTextur, "[NOT FOUND]")) TB_ERROR("Fehler beim Laden der alternativen Volumen-Textur, kein INI-Eintrag gefunden!", TB_ERROR);

            // Virtuelle Dateien erneut erstellen

            delete pVFile;
            pVFile = NULL;
            pVFile = new tbVFile;
            if(pVFile == NULL) TB_ERROR_OUT_OF_MEMORY(TB_ERROR);

            // Aus Datei laden

            if(pVFile->Init(acTextur)) TB_ERROR("Fehler beim Erstellen der virtuellen Datei!", TB_ERROR);

            hResult = D3DXCreateTextureFromFileInMemoryEx(tbDirect3D::GetDevice(),
                    (BYTE*)(pVFile->GetBuffer()) + pVFile->GetCursor(),
                    pVFile->GetSize() - pVFile->GetCursor(),
                    D3DX_DEFAULT, D3DX_DEFAULT,
                    1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
                    D3DX_DEFAULT, D3DX_DEFAULT,
                    ColorKey, &dinfo, NULL, 
                    (PDIRECT3DTEXTURE9*)(&m_pTexture));
        
            // Fehler?

            if(FAILED(hResult) || m_pTexture == NULL) TB_ERROR_DIRECTX("D3DXCreateTextureFromFileInMemoryEx", hResult, TB_ERROR);
        }
        // Bilddimensionen speichern

        m_2DSpriteInfo.fTextureHeight = (float)dinfo.Height;
        m_2DSpriteInfo.fTextureWidth = (float)dinfo.Width;

        // Die virtuellen Dateien wieder freigeben

        TB_SAFE_DELETE(pVFile);
    }


    // Sprite-Informationen laden

    ReadINIVolumeSpriteInfo(pINIReader,
                            pcINISection, 
                            "Sprite", 
                            &m_2DSpriteInfo);


    // Effektname aus INI laden

    char acEffect[256];
    pINIReader->ReadINIString(pcINISection, "Effect", acEffect, 256);
    if(!strcmp(acEffect, "[NOT FOUND]")) TB_ERROR("Fehler beim Laden des Sprite-Effekts!", TB_ERROR);
    // Effekt laden

    m_pEffect = new tbEffect; if(m_pEffect == NULL) TB_ERROR_OUT_OF_MEMORY(TB_ERROR);
    if(TB_OK != (tbRes = m_pEffect->Init(acEffect))) TB_ERROR("Fehler beim Erstellen des Sprite-Effekts!", TB_ERROR);
    // Effekt setzen

    if(TB_OK != m_pEffect->SetTechnique())  TB_ERROR("Fehler beim Setzen des Sprite-Effekts!", TB_ERROR);

    
    // Textur setzen

    hResult = m_pEffect->GetEffect()->SetTexture("Texture1", m_pTexture);
    // Fehler?

    if(FAILED(hResult)) TB_ERROR_DIRECTX("SetTexture", hResult, TB_ERROR);


    // INIReader wieder freigeben

    TB_SAFE_DELETE(pINIReader);

    return TB_OK;
}

// ******************************************************************

// Beginnt mit den Sprites

tbResult tb2DVolumeSprite::Begin()
{
    // Aktuellen Status speichern

    m_dwOldFVF = tbDirect3D::GetFVF();

    // Neues Vertexformat setzen

    tbDirect3D::SetFVF(TB_2DVOLUMESPRITE_FVF);

    // Mit dem Effekt beginnen

    m_iNumPasses = m_pEffect->Begin();

    // Vertexcursor setzen

    dwVertexCursor = 0;

    return TB_OK;
}

// ******************************************************************

// Beenden

tbResult tb2DVolumeSprite::End()
{
    // Wenn noch was im Puffer steht, dann wird jetzt gezeichnet.

    if(dwVertexCursor > 0)
    {
        DrawPuffer();
    }

    // Effekt beenden

    m_pEffect->End();

    // Wiederherstellen des alten Status

    tbDirect3D::SetFVF(m_dwOldFVF);

    return TB_OK;
}

// ******************************************************************

// Alle Sprites im Puffer sofort malen

tbResult tb2DVolumeSprite::DrawPuffer()
{
    // Jeden Durchgang des Effekts zeichnen

    for(int iPass = 0; iPass < m_iNumPasses; iPass++)
    {
        m_pEffect->Pass(iPass);

        tbDirect3D::GetDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST,
                                                 dwVertexCursor / 3,
                                                 aVertex,
                                                 sizeof(tb2DVolumeSpriteVertex));
    }

    // Vertexcursor zurücksetzen

    dwVertexCursor = 0;

    return TB_OK;
}

// ******************************************************************

// Diese Methode zeichnet ein Sprite.

tbResult tb2DVolumeSprite::DrawSprite(tbVector2 vPosition,
                                float fDepth,               // = 0.0f

                                DWORD dwNumber,             // = 0

                                const DWORD dwFlags,        // = TB_SVF_ALIGN_HLEFT | TB_SVF_ALIGN_VTOP | TB_SVF_DEPTH_ABSOLUTE

                                const tbColor& Color1,      // = tbColor(1.0f)

                                tbVector2 vScaling,         // = tbVector2(1.0f)

                                float fRotating)            // = 0.0f

{
    // Wenn rotiert werden soll muss transformated Sprite her

    if(fRotating != 0.0f)
    {
        tbMatrix    mTransformation;

        mTransformation = tbMatrixScaling(tbVector3(vScaling.x, vScaling.y, 1.0f));
        mTransformation *= tbMatrixRotationZ(fRotating);
        mTransformation *= tbMatrixTranslation(tbVector3(vPosition.x, vPosition.y, 0.0f));
        
        return DrawTransformedSprite(mTransformation, fDepth, dwNumber, dwFlags, Color1);
    }


    // Absolute Texturtiefen in Relative umrechnen

    if(dwFlags & TB_SVF_DEPTH_ABSOLUTE)
    {
        fDepth = fDepth / m_2DSpriteInfo.fTextureDepth;
    }


    // Relative Koordinaten in absolute umrechnen

    if(dwFlags & TB_SVF_RELATIVE)
    {
        vPosition.x *= tbDirect3D::GetScreenSize().x;
        vPosition.y *= tbDirect3D::GetScreenSize().y;
    }

    // Relative Skalierung in absolute umrechnen

    if(dwFlags & TB_SVF_RELATIVESCALING)
    {
        vScaling.x *= tbDirect3D::GetScreenSize().x / 640.0f;
        vScaling.y *= tbDirect3D::GetScreenSize().y / 480.0f;
    }


    tbVector2 vCursor(vPosition);
    // Breite des Sprites abfragen

    float fSpriteWidth = m_2DSpriteInfo.avSpriteWidthPix[dwNumber].x * vScaling.x;
    float fSpriteHight = m_2DSpriteInfo.avSpriteWidthPix[dwNumber].y * vScaling.y;


    // Cursor auf die horizontale Startposition setzen

    if((dwFlags & TB_SVF_ALIGN_HCENTER) || (dwFlags & TB_SVF_ALIGN_CENTER))
    {
        // Zentrieren

        vCursor.x -= 0.5f * (fSpriteWidth);
    }
    else if(dwFlags & TB_SVF_ALIGN_HRIGHT)
    {
        // Rechtsbündig

        vCursor.x -= fSpriteWidth-1;
    }
    else
    {
        // Linksbündig

    }


    // Cursor auf die vertikale Startposition setzen

    if((dwFlags & TB_SVF_ALIGN_VCENTER) || (dwFlags & TB_SVF_ALIGN_CENTER))
    {
        // vertikal zentrieren

        vCursor.y -= 0.5f * fSpriteHight;
    }
    else if(dwFlags & TB_SVF_ALIGN_VBOTTOM)
    {
        // unten ausrichten

        vCursor.y -= fSpriteHight-1;
    }
    else
    {
        // oben ausrichten

    }


    // Sechs Vertizes für das Sprite hinzufügen.

    // Dazu verwenden wir Dreieckslisten - jeweils sechs Vertizes

    // beschreiben ein Viereck.


    // Erster Vertex: links oben

    aVertex[dwVertexCursor].vPosition = tbVector3(vCursor.x, vCursor.y, 0.0f);
    aVertex[dwVertexCursor].fRHW = 1.0f;
    aVertex[dwVertexCursor].Diffuse = Color1;
    aVertex[dwVertexCursor].vTexture = tbVector3(m_2DSpriteInfo.avTopLeft[dwNumber].x, m_2DSpriteInfo.avTopLeft[dwNumber].y, fDepth);

    // Zweiter Vertex: rechts oben

    aVertex[dwVertexCursor + 1].vPosition = tbVector3(vCursor.x + fSpriteWidth, vCursor.y, 0.0f);
    aVertex[dwVertexCursor + 1].fRHW = 1.0f;
    aVertex[dwVertexCursor + 1].Diffuse = Color1;
    aVertex[dwVertexCursor + 1].vTexture.x = m_2DSpriteInfo.avBottomRight[dwNumber].x;
    aVertex[dwVertexCursor + 1].vTexture.y = m_2DSpriteInfo.avTopLeft[dwNumber].y;
    aVertex[dwVertexCursor + 1].vTexture.z = fDepth;

    // Dritter Vertex: rechts unten

    aVertex[dwVertexCursor + 2].vPosition = tbVector3(vCursor.x + fSpriteWidth, vCursor.y + fSpriteHight, 0.0f);
    aVertex[dwVertexCursor + 2].fRHW = 1.0f;
    aVertex[dwVertexCursor + 2].Diffuse = Color1;
    aVertex[dwVertexCursor + 2].vTexture = tbVector3(m_2DSpriteInfo.avBottomRight[dwNumber].x, m_2DSpriteInfo.avBottomRight[dwNumber].y, fDepth);

    // Vierter Vertex = erster Vertex

    aVertex[dwVertexCursor + 3] = aVertex[dwVertexCursor];

    // Fünfter Vertex = dritter Vertex

    aVertex[dwVertexCursor + 4] = aVertex[dwVertexCursor + 2];

    // Sechster Vertex: links unten

    aVertex[dwVertexCursor + 5].vPosition = tbVector3(vCursor.x, vCursor.y + fSpriteHight, 0.0f);
    aVertex[dwVertexCursor + 5].fRHW = 1.0f;
    aVertex[dwVertexCursor + 5].Diffuse = Color1;
    aVertex[dwVertexCursor + 5].vTexture.x = m_2DSpriteInfo.avTopLeft[dwNumber].x;
    aVertex[dwVertexCursor + 5].vTexture.y = m_2DSpriteInfo.avBottomRight[dwNumber].x;
    aVertex[dwVertexCursor + 5].vTexture.z = fDepth;

    // Vertexcursor aktualisieren

    dwVertexCursor += 6;


    // Wenn das Vertex-Array voll ist, dann wird jetzt gezeichnet.

    if(dwVertexCursor >= 600)
    {
        DrawPuffer();
    }

    return TB_OK;
}

// ******************************************************************

// Sprite mit Transformationsmatrix zeichnen

tbResult tb2DVolumeSprite::DrawTransformedSprite(tbMatrix mTransformation,
                                           float fDepth,            // = 0.0f

                                           DWORD dwNumber,          // = 0

                                           const DWORD dwFlags,     // = TB_SF_ALIGN_HLEFT | TB_SF_ALIGN_VTOP | TB_SVF_DEPTH_ABSOLUTE

                                           const tbColor& Color1)   // = tbColor(1.0f)

{
    // Relative Texturtiefen in absolute umrechnen

    if(dwFlags & TB_SVF_DEPTH_ABSOLUTE)
    {
        fDepth = fDepth / m_2DSpriteInfo.fTextureDepth;
    }

    // Relative Koordinaten in absolute umrechnen

    if(dwFlags & TB_SVF_RELATIVE)
    {
        mTransformation.m41 *= tbDirect3D::GetScreenSize().x;
        mTransformation.m42 *= tbDirect3D::GetScreenSize().y;
    }

    // Relative Größe in absolute umrechnen

    if(dwFlags & TB_SVF_RELATIVESCALING)
    {
        mTransformation.m11 *= tbDirect3D::GetScreenSize().x / 640.0f;
        mTransformation.m22 *= tbDirect3D::GetScreenSize().y / 480.0f;
    }

    tbVector2 vCursor(0.0f);
    // Breite des Sprites abfragen

    float fSpriteWidth = m_2DSpriteInfo.avSpriteWidthPix[dwNumber].x;
    float fSpriteHight = m_2DSpriteInfo.avSpriteWidthPix[dwNumber].y;

    // Cursor auf die horizontale Startposition setzen

    if((dwFlags & TB_SVF_ALIGN_HCENTER) || (dwFlags & TB_SVF_ALIGN_CENTER))
    {
        // Zentrieren

        vCursor.x = -0.5f * (fSpriteWidth);
    }
    else if(dwFlags & TB_SVF_ALIGN_HRIGHT)
    {
        // Rechtsbündig

        vCursor.x = -(fSpriteWidth-1);
    }
    else
    {
        // Linksbündig

    }

    // Cursor auf die vertikale Startposition setzen

    if((dwFlags & TB_SVF_ALIGN_VCENTER) || (dwFlags & TB_SVF_ALIGN_CENTER))
    {
        // vertikal zentrieren

        vCursor.y = -0.5f * (fSpriteHight);
    }
    else if(dwFlags & TB_SVF_ALIGN_VTOP)
    {
        // oben ausrichten

        vCursor.y = -(fSpriteHight-1);
    }
    else
    {
        // unten ausrichten

    }


    // Sechs Vertizes für das Sprite hinzufügen.

    // Dazu verwenden wir Dreieckslisten - jeweils sechs Vertizes

    // beschreiben ein Viereck.


    // Erster Vertex: links oben

    aVertex[dwVertexCursor].vPosition = tbVector3(vCursor.x, vCursor.y, 0.0f);
    aVertex[dwVertexCursor].vPosition = tbVector3TransformCoords(aVertex[dwVertexCursor].vPosition, mTransformation);
    aVertex[dwVertexCursor].fRHW = 1.0f;
    aVertex[dwVertexCursor].Diffuse = Color1;
    aVertex[dwVertexCursor].vTexture = tbVector3(m_2DSpriteInfo.avTopLeft[dwNumber].x, m_2DSpriteInfo.avTopLeft[dwNumber].y, fDepth);

    // Zweiter Vertex: rechts oben

    aVertex[dwVertexCursor + 1].vPosition = tbVector3(vCursor.x + fSpriteWidth, vCursor.y, 0.0f);
    aVertex[dwVertexCursor + 1].vPosition = tbVector3TransformCoords(aVertex[dwVertexCursor + 1].vPosition, mTransformation);
    aVertex[dwVertexCursor + 1].fRHW = 1.0f;
    aVertex[dwVertexCursor + 1].Diffuse = Color1;
    aVertex[dwVertexCursor + 1].vTexture.x = m_2DSpriteInfo.avBottomRight[dwNumber].x;
    aVertex[dwVertexCursor + 1].vTexture.y = m_2DSpriteInfo.avTopLeft[dwNumber].y;
    aVertex[dwVertexCursor + 1].vTexture.z = fDepth;

    // Dritter Vertex: rechts unten

    aVertex[dwVertexCursor + 2].vPosition = tbVector3(vCursor.x + fSpriteWidth, vCursor.y + fSpriteHight, 0.0f);
    aVertex[dwVertexCursor + 2].vPosition = tbVector3TransformCoords(aVertex[dwVertexCursor + 2].vPosition, mTransformation);
    aVertex[dwVertexCursor + 2].fRHW = 1.0f;
    aVertex[dwVertexCursor + 2].Diffuse = Color1;
    aVertex[dwVertexCursor + 2].vTexture = tbVector3(m_2DSpriteInfo.avBottomRight[dwNumber].x, m_2DSpriteInfo.avBottomRight[dwNumber].y, fDepth);

    // Vierter Vertex = erster Vertex

    aVertex[dwVertexCursor + 3] = aVertex[dwVertexCursor];

    // Fünfter Vertex = dritter Vertex

    aVertex[dwVertexCursor + 4] = aVertex[dwVertexCursor + 2];

    // Sechster Vertex: links unten

    aVertex[dwVertexCursor + 5].vPosition = tbVector3(vCursor.x, vCursor.y + fSpriteHight, 0.0f);
    aVertex[dwVertexCursor + 5].vPosition = tbVector3TransformCoords(aVertex[dwVertexCursor + 5].vPosition, mTransformation);
    aVertex[dwVertexCursor + 5].fRHW = 1.0f;
    aVertex[dwVertexCursor + 5].Diffuse = Color1;
    aVertex[dwVertexCursor + 5].vTexture.x = m_2DSpriteInfo.avTopLeft[dwNumber].x;
    aVertex[dwVertexCursor + 5].vTexture.y = m_2DSpriteInfo.avBottomRight[dwNumber].x;
    aVertex[dwVertexCursor + 5].vTexture.z = fDepth;

    // Vertexcursor aktualisieren

    dwVertexCursor += 6;

    // Wenn das Vertex-Array voll ist, dann wird jetzt gezeichnet.

    if(dwVertexCursor >= 600)
    {
        DrawPuffer();
    }

    return TB_OK;
}

// ****************************************************************** 

8

13.08.2003, 19:47

Saubere Arbeit :)

Endlich mal jemand der die TriBase erweitert statt einfach zu nutzen ;)

Lass uns die TriBase besser als die Engine von Carmack (Quake2) machen ^^ :D

cya

Snorky

Frischling

  • »Snorky« ist der Autor dieses Themas

Beiträge: 34

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

9

13.08.2003, 19:54

Nachtrag

Puh, das müßte eigentlich alles gewesen sein. Nun viel Spaß beim copy & pasten.
Hm, war nicht was mit in Code-Format anzeigen? Ja, sowas fällt einem natürlich wieder zu spät ein. Wer also keine Kiffersmilies im Quelltext haben möchte, sollte die beiden Stellen noch mit der Hand nachbessern. Da fehlt nur 8) hehe. Okok, ich gebs zu, ein dummer Scherz, also es ist eine Acht und eine runde Klammer zu.

Zu Benutzen sind die Sprites jetzt wie die Texte auch. Allerdings benötigt man beim Laden noch einen Effekt. Den packt man wieder schön eine Datei, wie z.B. NoBlur.fx mit folgendem Inhalt:

Quellcode

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
STRING  Description      = "NoBlur-Effect";
TEXTURE Texture1;

TECHNIQUE T1
{
    PASS P1
    {
        // Textur setzen
        Texture[0]      = <Texture1>;

        // kein Z-Buffer
        ZEnable         = False;
        ZWriteEnable        = False;

        // Alpha-Blending aktivieren
        AlphaBlendEnable    = True;
        SrcBlend        = SrcAlpha;
        DestBlend       = InvSrcAlpha;

        // Texturestages
        AlphaOp[0]      = Modulate;
        AlphaArg1[0]        = Texture;
        AlphaArg2[0]        = Current;
        AlphaOp[1]      = Disable;

        ColorOp[0]      = Modulate;
        ColorArg1[0]        = Texture;
        ColorArg2[0]        = Current;
        ColorOp[1]      = Disable;

        // Renderstages
        // kein blur
        Magfilter[0]        = Point;
        Minfilter[0]        = Point;
    }
}

Wuha, ich hab an den Code-Button gedacht ;p

Hier hat man nicht diesen Weichzeichnereffekt, wie er vielleicht für 2D-Sprites auch sein sollte. Wer anderer Meinung ist, kann natürlich den Mag- und Minfilter auf Linear setzen et voilà!
Das sollte man nämlich auf jeden Fall für die Volumentexturen verwenden.

Kommen wir nun zum INI-File, die flexible Methode Sprites zu lesen, z.B. Sprites.ini:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
; einfache 2D-Sprites Mauszeigerbilder
[Mauszeiger]
Texture     = Data\\Mauszeiger.bmp
Effect      = Data\\NoBlur.fx
ColorKey    = 0, 1, 0, 1
Sprite0     = 0, 0, 30, 30


; Volumentextur Explosion z.B. die aus Kapitel 2.12
[Explosion]
Texture     = Data\\Explosion.dds
TextureAlt  = Data\\Explosion009.bmp
Effect      = Data\\Volume.fx
ColorKey    = 0, 0, 0, 0
Sprite0     = 0, 0, 256, 256


Der ColorKey muss nicht angegeben werden.
Unter SpriteX stehen jetzt die Koordinaten eines einzelnen Teilbildes in der ganzen Textur. Man kann also wieder mehrere Sprites in einem Bild unterbekommen, indem man z.B. folgendes macht:
Sprite0 = 0, 0, 50, 50
Sprite1 = 50, 0, 50, 50
Sprite2 = 100, 0, 50, 50
et cetera dreck cetera

Die ersten zwei Zahlen geben den Startpunkt des Sprites an und die letzten zwei die Länge und die Höhe. So braucht man nicht für jedes neue Sprite eine neue Textur. Das geht theoretisch auch bei Volumentexturen. Hier gibt es aber noch einen zusätzlichen Eintrag namens TextureAlt. Der sagt ein einfaches Bild an, falls das Laden der dds-Datei fehlgeschlagen ist, weil die Grafikkarte womöglich keine Volumentexturen unterstützt. So kann man wenigstens noch ein normales Bild anzeigen, wie z.B. eins mit einer blutrot aufgemalten Schrift "Tja, normalerweise würden Sie heir coole Wolken-wabbel-effekte sehen, aber Sie mussten ja wieder an der Grafikkarte sparen!". }>

Snorky

Frischling

  • »Snorky« ist der Autor dieses Themas

Beiträge: 34

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

10

13.08.2003, 20:12

Beispielprogramm

Wer jetzt noch ein Beispielprogramm braucht um mit der neuen 2D-Sprite-Klasse umgehen zu können, der kann sich mal das leicht modifizierte Beispielprogramm zu Kapitel 3 ansehen, was ich verwendet habe um meine Klasse zu testen.

Quellcode

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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
// Kapitel 3
// Beispielprogramm 03
// ===================
// Hier wird gezeigt, wie man Texte darstellt.
// ... und jetzt auch 2D-Sprites benutzt

#include <TriBase.h>
#include "Resource.h"


// ******************************************************************
// Globale Variablen
tbConfig            g_Config;           // Konfigurationsstruktur
tbFont*             g_pFont1 = NULL;    // Erste Schriftart
tbFont*             g_pFont2 = NULL;    // Zweite Schriftart
float               g_fTime = 0.0f;     // Globaler Zeitzähler
tb2DSprite*         g_pSprite = NULL;   // Sprites
tb2DVolumeSprite*   g_pVolumeSprite = NULL; // Volumensprite

// ******************************************************************
// Die Move-Funktion
tbResult MoveProc(float fNumSecsPassed)
{
    // Den Zeitzähler aktualisieren
    g_fTime += fNumSecsPassed;

    return TB_OK;
}

// ******************************************************************
// Die Render-Funktion
tbResult RenderProc(float fNumSecsPassed)
{
    char        acText[256];
    tbVector2   vPosition;
    tbMatrix    mTransformation;
    POINT       Cursor;


    // Puffer leeren und die Szene beginnen
    tbDirect3D::GetDevice()->Clear(0, NULL, D3DCLEAR_TARGET, tbColor(0.0f, 0.0f, 0.1f), 1.0f, 0);
    tbDirect3D::GetDevice()->BeginScene();

    // ------------------------------------------------------------------

    // Volumensprites
    float fTmpTime = g_fTime / 1.0f;
    g_pVolumeSprite->Begin();
    g_pVolumeSprite->DrawSprite(
        tbVector2((float)(g_Config.Direct3D.VideoMode.Width) / 2.0f, (float)(g_Config.Direct3D.VideoMode.Height) / 2.0f),
        fTmpTime, 0, TB_SVF_ALIGN_CENTER | TB_SVF_DEPTH_RELATIVE, tbColor(1.0f, 1.0f, 1.0f, 1.0f), tbVector2(1.0f));
    g_pVolumeSprite->End();

    // ------------------------------------------------------------------

    // Text mit der ersten Schriftart zeichnen, bei (10, 10)
    g_pFont1->Begin();
    g_pFont1->DrawText(tbVector2(10.0f, 10.0f), "Das ist die Schriftart <Futura>!");
    g_pFont1->End();

    // Text mit der zweiten Schriftart zeichnen, bei (10, 30)
    g_pFont2->Begin();
    g_pFont2->DrawText(tbVector2(10.0f, 30.0f), "Das ist die Schriftart <Courier New>!");
    g_pFont2->End();

    // ------------------------------------------------------------------

    // Die vergangene Zeit seit Programmstart und die Framerate anzeigen.
    // Um float-Werte in einen String umzuwandeln, verwenden wir die sprintf-Funktion.
    // Wir platzieren den Text 100 Einheiten links vom rechten Bildschirmende.
    // Die Framerate wird berechnet, indem wir den Kehrwert der vergangenen Zeit
    // seit dem letzten Frame berechnen. Beispiel: 0.01 Sekunden pro Frame -> 100 FPS.
    sprintf(acText, "Zeit: %.2f\nFPS: %.2f", g_fTime, 1.0f / fNumSecsPassed);
    g_pFont1->Begin();
    g_pFont1->DrawText(tbVector2((float)(g_Config.Direct3D.VideoMode.Width) - 100.0f, 50.0f),
                       acText,                      // Der Text
                       TB_FF_ALIGN_HLEFT,           // Links ausrichten
                       -1,                          // Textlänge automatisch ermitteln
                       tbColor(0.25f, 1.0f, 0.25f), // Startfarbe (links), grün
                       tbColor(1.0f, 1.0f, 1.0f),   // Endfarbe (rechts), weiß
                       tbVector2(0.75f, 1.0f),      // Skalierung (75% auf x-Achse)
                       -2.0f,                       // Zeichen um 2 Pixel enger
                       2.0f,                        // Kursivität: 2 Pixel
                       0.0f,                        // Standardzeilenabstand
                       50.0f,                       // Tab-Stopps alle 50 Pixel
                       0.0f);                       // x-Abstand = 0

    // Viele kleine Strings, die teilweise transparent sind, herumfliegen lassen (zentriert)
    for(int iText = 0; iText < 10; iText++)
    {
        // Position des Texts berechnen
        vPosition.x = (float)(g_Config.Direct3D.VideoMode.Width) / 2.0f;
        vPosition.y = (float)(g_Config.Direct3D.VideoMode.Height) / 2.0f;
        vPosition.x += sinf(g_fTime * 0.25f * (float)(iText)) * cosf(g_fTime * 0.25f + (float)(iText)) * 250.0f;
        vPosition.y += sinf(g_fTime * 0.25f * (float)(iText)) + cosf(g_fTime * 0.25f + (float)(iText)) * 250.0f;

        // Text zeichnen, mit schwankender Skalierung und Farbe
        g_pFont1->DrawText(vPosition, "Text", TB_FF_ALIGN_HCENTER, -1,
                           tbColor(sinf(g_fTime + (float)(iText)), cosf(g_fTime + (float)(iText)), g_fTime * 0.25f, 1.0f),
                           tbColor(0.0f, 1.0f, 0.0f, 0.5f + sinf(g_fTime * 0.25f + (float)(iText)) * 0.25f),
                           tbVector2(fabsf(0.5f + sinf(g_fTime + (float)(iText)) * 4.0f), 2.0f),
                           0.0f, -2.0f,
                           0.0f, 50.0f, 0.0f);
    }

    // ------------------------------------------------------------------
    
    // Frei transformierten Text schreiben. Wir verwenden eine Rotationsmatrix, um den Text
    // zu drehen und eine Translationsmatrix, um ihn zum Bildmittelpunkt zu schieben.
    mTransformation = tbMatrixScaling(2.0f) * tbMatrixRotationZ(g_fTime);
    mTransformation *= tbMatrixTranslation(tbVector3((float)(g_Config.Direct3D.VideoMode.Width) / 2.0f,
                                                     (float)(g_Config.Direct3D.VideoMode.Height) / 2.0f, 0.0f));
    g_pFont1->DrawTransformedText(mTransformation, "Rotierender Text", TB_FF_ALIGN_HCENTER | TB_FF_ALIGN_VCENTER, -1,
                                  tbColor(0.25f, 1.0f, 0.25f, 0.5f), tbColor(1.0f),
                                  0.0f);
    g_pFont1->End();

    // ------------------------------------------------------------------

    // Wir schreiben die Koordinaten des Mauscursors genau dort hin, wo der Cursor auch ist.
    g_pFont2->Begin();
    GetCursorPos(&Cursor);
    sprintf(acText, "(%d, %d)", Cursor.x, Cursor.y);
//  sprintf(acText, "%f, %f, %f", g_pVolumeSprite->GetInfo().fTextureHeight, g_pVolumeSprite->GetInfo().fTextureHeight, g_pVolumeSprite->GetInfo().fTextureDepth);
    sprintf(acText, "%f", fTmpTime);
    g_pFont2->DrawText(tbVector2((float)(Cursor.x), (float)(Cursor.y)),
                       acText, TB_FF_ALIGN_HCENTER | TB_FF_ALIGN_VCENTER, -1,
                       tbColor(1.0f, 0.75f, 0.75f), tbColor(0.0f, 1.0f, 1.0f),
                       tbVector2(1.5f, 1.5f),
                       0.0f, 0.0f,
                       0.0f, 50.0f, 0.0f);
    g_pFont2->End();

    // ------------------------------------------------------------------

    // Sprite malen
    g_pSprite->Begin();
    for(LONG l=0; l<1; l++)
    {
        g_pSprite->DrawSprite(tbVector2((float)Cursor.x, (float)Cursor.y), 0, TB_SF_ALIGN_HLEFT | TB_SF_ALIGN_VTOP, tbColor(1.0f, 1.0f, 1.0f, 0.5f));
        mTransformation = tbMatrixScaling(1.0f) * tbMatrixRotationZ(g_fTime);
        mTransformation *= tbMatrixTranslation(tbVector3((float)(g_Config.Direct3D.VideoMode.Width) / 2.0f, (float)(g_Config.Direct3D.VideoMode.Height) / 2.0f, 0.0f));
        g_pSprite->DrawTransformedSprite(mTransformation,0,TB_SF_ALIGN_CENTER,tbColor(1.0f,1.0f,1.0f,0.5f));
    }
    g_pSprite->End();

    // ------------------------------------------------------------------
    // Szene beenden und darstellen
    tbDirect3D::GetDevice()->EndScene();
    tbDirect3D::GetDevice()->Present(NULL, NULL, NULL, NULL);

    return TB_OK;
}

// ******************************************************************
// Initialisierung der Schriftarten
tbResult InitFonts()
{
    // Erste Schriftart...
    g_pFont1 = new tbFont;
    if(g_pFont1->Init("Data\\Futura_8_22.tga", "Data\\Futura_8_22.tbf"))
    {
        // Fehler...
        return TB_ERROR;
    }

    // Zweite Schriftart...
    g_pFont2 = new tbFont;
    if(g_pFont2->Init("Data\\Courier New_9_18.tga", "Data\\Courier New_9_18.tbf"))
    {
        // Fehler...
        return TB_ERROR;
    }

    // Mauszeiger laden
    g_pSprite = new tb2DSprite;
    if(g_pSprite->Init("Data\\Sprites.ini", "Mauszeiger"))
    {
        // Fehler...
        return TB_ERROR;
    }

    // Explosion laden
    g_pVolumeSprite = new tb2DVolumeSprite;
    if(g_pVolumeSprite->Init("Data\\Sprites.ini", "Explosion"))
    {
        // Fehler...
        return TB_ERROR;
    }

    return TB_OK;
}

// ******************************************************************
// Aufräumen
tbResult CleanUp()
{
    // Alle Fonts löschen
    TB_SAFE_DELETE(g_pFont1);
    TB_SAFE_DELETE(g_pFont2);

    // Sprite löschen
    TB_SAFE_DELETE(g_pSprite);
    TB_SAFE_DELETE(g_pVolumeSprite);

    // Texturmanager beenden
    tbTextureManager::Exit();

    // Direct3D beenden
    tbDirect3D::Exit();

    // Die TriBase-Engine herunterfahren
    tbExit();

    return TB_OK;
}

// ******************************************************************
// Windows-Hauptfunktion
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   char* pcCommandLine,
                   int iShowCommand)
{
    int r;

    // TriBase-Engine initialisieren
    tbInit();

    // Konfiguration abfragen
    if(r = tbDoConfigDialog(&g_Config))
    {
        if(r == TB_CANCELED) return 0;
        else
        {
            // Fehler!
            MessageBox(NULL, "Fehler im Konfigurationsdialog!", "Fehler",
                       MB_OK | MB_ICONEXCLAMATION);
            return 1;
        }
    }

    // Direct3D initialisieren
    if(tbDirect3D::Init(&g_Config,
                         "Beispielprogramm Nr. 3: Texte",
                         NULL,
                         LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1))))
    {
        // Fehler!
        MessageBox(NULL, "Fehler bei der Direct3D-Initialisierung!", "Fehler",
                   MB_OK | MB_ICONEXCLAMATION);
        CleanUp();
        return 1;
    }

    // Texturmanager erstellen
    if(tbTextureManager::Init())
    {
        // Fehler!
        MessageBox(NULL, "Texturmanager konnte nicht initialisiert werden!", "Fehler",
                   MB_OK | MB_ICONEXCLAMATION);
        CleanUp();
        return 1;
    }

    // Die beiden Schriftarten laden
    if(InitFonts())
    {
        // Fehler!
        MessageBox(NULL, "Fehler beim Laden der Schriftarten!",
                   "Fehler", MB_OK | MB_ICONEXCLAMATION);
        CleanUp();
        return 1;
    }

    // Nachrichtenschleife betreten
    if(tbDoMessageLoop(MoveProc, RenderProc))
    {
        MessageBox(tbDirect3D::GetWindow(), "Fehler beim Zeichnen!",
                   "Fehler", MB_OK | MB_ICONEXCLAMATION);
        CleanUp();
        return 1;
    }


    // Aufräumen
    CleanUp();

    return 0;
}

// ******************************************************************


Was Euch jetzt nur noch fehlt ist ein Bild namens Mauszeiger.bmp, das mindestens 30x30 Pixel hat, Knallgrün als ColorKey verwendet und sich mit dem ganzen anderen Schnickschnack in einem Data-Verzeichnis befindet. Das läßt sich aber alles leicht in der INI ändern.

Und nun viel Spaß
:hop:

Werbeanzeige