Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: C++: Tuli -efekti

Sivun loppuun

peki [14.08.2004 23:31:05]

#

Teinpä tässä huvikseni pienen tuli-efektin sdl:lle.
perustuu palettiin ja kylmennys karttaan.
Voit piirtää myös omia "poltettavia" kohteita.
Koodi on yksinkertaista, joten siitä selviää idea tutkimalla hetken.
Kiitos T.M.:lle php:llä toteutetusta palettiliukugeneraattorista, jolla loin tämän ohjelman paletin.
Käännetty exe kylmennyskarttoineen ja polttokuvineen löytyy täältä.
http://koti.mbnet.fi/peku1/Fire.zip

Edit: Tein hiirestä palavan

Edit2: Tein koodiin uuden räjähdyssysteemin. Suosittelen kokeilemaan tätä uutta versiota. Se vain yksinkertaisesti on cool. Korjasin myös muutaman bugin.

Edit3: Virittelin räjähdystä ja hiiren kursoria kauniimmaksi. (päivitin myös exen)

#include "SDL.h"
#include <stdlib.h>
#include <math.h>

#define PARTIKKELEJA 360

enum {
  SCREENWIDTH = 640,
  SCREENHEIGHT = 480,
  SCREENBPP = 32,
  SCREENFLAGS = SDL_ANYFORMAT
};

struct particle // partikkeli
{
    double x,y;
    double velx, vely;
    double accx, accy;
    int vari;
    bool kuollut;
    int aika;
};

struct pikseli  // pikseli data struktuuri kuvaa varten
{
    int x,y;
    int vari;
};

double costable[360];
double sintable[360];

particle partikkelit[PARTIKKELEJA];
int kuolleet = 0;

pikseli kuvadata[SCREENWIDTH * SCREENHEIGHT];  // poltettavan kuvan data
int kuvadatapituus;    // datan pituus

SDL_Surface *cooler; // kylmennys kartta
int cooloffset = 0;  // offsetti 0 kohtaan(selvitän myöhemmin)

int buffer[SCREENWIDTH][SCREENHEIGHT];  // puskuri 1
int buffer2[SCREENWIDTH][SCREENHEIGHT]; // puskuri 2

// väripaletti (surkea, tiedän)
Uint32 paletti[] = {0, 327680, 720896, 1048576, 1376256, 1769472, 2097152, 2424832, 2818048, 3145728, 3473408, 3801088, 4194304, 4521984, 4849664, 5242880, 5570560, 5898240, 6291456, 6619136, 6946816, 7340032, 7667712, 7995392, 8388608, 8716288, 9043968, 9371648, 9764864, 10092544, 10420224, 10813440, 11141120, 11468800, 11862016, 12189696, 12517376, 12910592, 13238272, 13565952, 13959168, 14286848, 14614528, 14942208, 15335424, 15663104, 15990784, 16384000, 16711680, 16712192, 16712704, 16713216, 16713984, 16714496, 16715008, 16715520, 16716032, 16716544, 16717312, 16717824, 16718336, 16718848, 16719360, 16719872, 16720384, 16721152, 16721664, 16722176, 16722688, 16723200, 16723712, 16724224, 16724992, 16725504, 16726016, 16726528, 16727040, 16727552, 16728320, 16728832, 16729344, 16729856, 16730368, 16730880, 16731392, 16732160, 16732672, 16733184, 16733696, 16734208, 16734720, 16735488, 16736000, 16736512, 16737024, 16737536, 16738048, 16738560, 16739328, 16739840, 16740352, 16740864, 16741376, 16741888, 16742656, 16743168, 16743680, 16744192, 16744704, 16745216, 16745728, 16746496, 16747008, 16747520, 16748032, 16748544, 16749056, 16749568, 16750336, 16750848, 16751360, 16751872, 16752384, 16752896, 16753664, 16754176, 16754688, 16755200, 16755456, 16755712, 16755968, 16756224, 16756480, 16756736, 16757248, 16757504, 16757760, 16758016, 16758272, 16758528, 16758784, 16759040, 16759296, 16759552, 16759808, 16760064, 16760320, 16760832, 16761088, 16761344, 16761600, 16761856, 16762112, 16762368, 16762624, 16762880, 16763136, 16763392, 16763648, 16763904, 16764416, 16764672, 16764928, 16765184, 16765440, 16765696, 16765952, 16766208, 16766464, 16766720, 16766976, 16767232, 16767488, 16767744, 16768256, 16768512, 16768768, 16769024, 16769280, 16769536, 16769792, 16770048, 16770304, 16770560, 16770816, 16771072, 16771328, 16771840, 16772096, 16772352, 16772608, 16772864, 16773120, 16773376, 16773632, 16773888, 16774144, 16774400, 16774656, 16774912, 16775424, 16775680, 16775936, 16776192, 16776448, 16776704, 16776960, 16776965, 16776970, 16776976, 16776981, 16776986, 16776991, 16776996, 16777002, 16777007, 16777012, 16777017, 16777022, 16777028, 16777033, 16777038, 16777043, 16777048, 16777054, 16777059, 16777064, 16777069, 16777074, 16777080, 16777085, 16777090, 16777095, 16777101, 16777106, 16777111, 16777116, 16777121, 16777127, 16777132, 16777137, 16777142, 16777147, 16777153, 16777158, 16777163, 16777168, 16777173, 16777179, 16777184, 16777189, 16777194, 16777199, 16777205, 16777210, 16777215, 0};

void particleinit()
{
    // alusta partikkelit
    partikkelit[0].x = rand() % SCREENWIDTH; // räjähdyksen keskipiste
    partikkelit[0].y = rand() % SCREENHEIGHT; // räjähdyksen keskipiste
    for (int i=0;i<=PARTIKKELEJA;i++)
    {
        partikkelit[i].x = partikkelit[0].x;
        partikkelit[i].y = partikkelit[0].y;
        partikkelit[i].vari = 255; // väri kirkkaaksi
        partikkelit[i].aika = 200; // elinaika täysille
        partikkelit[i].velx = rand()%7 * costable[i]; // partikkeleja 360 -> ei tartte skaalata arvoa
        partikkelit[i].vely = rand()%7 * sintable[i] - 3;
        partikkelit[i].accy = 0.2; // gravitaatio
        partikkelit[i].accx = 0.0; // ei x suuntaan tapahtuvaa kiihdytystä
        partikkelit[i].kuollut = false; // ei ole kuollut
    }
}

 // Palauttaa pikselin (x,y) arvon
 // Pinnan täytyy olla lukittuna tätä tehdessä!
 // "_fastcall" käskee kääntäjää välittämään parametrit rekistereissä. Kutsuminen on siis nopeampaa.
Uint32 _fastcall getpixel(SDL_Surface *surface, int x, int y)
{
    int bpp = surface->format->BytesPerPixel;
    // p on osoitin pikseliin, jonka haluamme kopioida
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        return *p;

    case 2:
        return *(Uint16 *)p;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
            return p[0] << 16 | p[1] << 8 | p[2];
        else
            return p[0] | p[1] << 8 | p[2] << 16;

    case 4:
        return *(Uint32 *)p;

    default:
        return 0;       // ei pitäisi tapahtua.
    }
}

 // Aseta pikseli (x, y) annettuun arvoon
 // Pinnan täytyy olla lukittuna tätä tehdessä!
void _fastcall putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
    int bpp = surface->format->BytesPerPixel;
    // p on osoitin pikseliin, jonka haluamme asettaa
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        *p = pixel;
        break;

    case 2:
        *(Uint16 *)p = pixel;
        break;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
            p[0] = (pixel >> 16) & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = pixel & 0xff;
        } else {
            p[0] = pixel & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = (pixel >> 16) & 0xff;
        }
        break;

    case 4:
        *(Uint32 *)p = pixel;
        break;
    }
}


void DrawScene(SDL_Surface* surface, SDL_Event* event)
{
    // Lukitse pinta, jotta voimme käsitellä pikseleitä suoraan
    if ( SDL_MUSTLOCK(surface) ) {
        if ( SDL_LockSurface(surface) < 0 ) {
            fprintf(stderr, "Can't lock the screen: %s\n", SDL_GetError());
            return;
        }
    }

    // piirretään pohjakuva
    for (int x=0;x<=kuvadatapituus;x++)
        {
            buffer[kuvadata[x].x][kuvadata[x].y] = kuvadata[x].vari;
            // hiiren kohdalle pikseli
            if (event->motion.x > 8 && event->motion.x < SCREENWIDTH-8)
                if (event->motion.y > 8 && event->motion.y < SCREENHEIGHT-8)
                {
                    for (int i=-8; i<=8; i++)
                    {
                        buffer[event->motion.x + i][event->motion.y] = 255;
                        buffer[event->motion.x][event->motion.y + i] = 255;
                    }
                }
        }

    bool alldead = true; // kaikki kuolleita?
    for (int i=0;i<PARTIKKELEJA;i++)
    {
        if (partikkelit[i].kuollut == false) // jos ei kuollut
        {
            // Jos on ruudulla siirtojen jälkeen
            if (partikkelit[i].x + partikkelit[i].velx >= 3 && partikkelit[i].x + partikkelit[i].velx <= SCREENWIDTH-3)
            {
                if (partikkelit[i].y + partikkelit[i].vely >= 3 && partikkelit[i].y + partikkelit[i].vely <= SCREENHEIGHT-3)
                {
                    // siirrä
                    partikkelit[i].velx += partikkelit[i].accx;
                    partikkelit[i].vely += partikkelit[i].accy;
                    partikkelit[i].x += partikkelit[i].velx;
                    partikkelit[i].y += partikkelit[i].vely;
                    partikkelit[i].aika -= 1; //laske aikaa
                    if (partikkelit[i].vari - 6 >= 0) partikkelit[i].vari -= 6; //vähennä väriä

                    if (partikkelit[i].aika < 1 || partikkelit[i].vari <= 6) partikkelit[i].kuollut = true; // jos aika 0 -> tapa

                    // partikkeli ruutuun
                    buffer[(int)partikkelit[i].x][(int)partikkelit[i].y] = partikkelit[i].vari;

                    buffer[(int)partikkelit[i].x+1][(int)partikkelit[i].y+1] = partikkelit[i].vari;
                    buffer[(int)partikkelit[i].x-1][(int)partikkelit[i].y-1] = partikkelit[i].vari;
                    buffer[(int)partikkelit[i].x+1][(int)partikkelit[i].y-1] = partikkelit[i].vari;
                    buffer[(int)partikkelit[i].x-1][(int)partikkelit[i].y+1] = partikkelit[i].vari;

                    buffer[(int)partikkelit[i].x+1][(int)partikkelit[i].y] = partikkelit[i].vari;
                    buffer[(int)partikkelit[i].x-1][(int)partikkelit[i].y] = partikkelit[i].vari;
                    buffer[(int)partikkelit[i].x][(int)partikkelit[i].y-1] = partikkelit[i].vari;
                    buffer[(int)partikkelit[i].x][(int)partikkelit[i].y+1] = partikkelit[i].vari;

                    alldead = false; // ei ole kaikki kuolleita.
                }
            }
        }
    }
    if (alldead == true) particleinit(); // jos kaikki kuolleita -> alusta

    Uint32 c1, c2, c3, c4;
    int cfr;

    // käydään koko ruutu läpi
    for (int x=1;x<SCREENWIDTH-1;x++)
        for (int y=1;y<SCREENHEIGHT-1;y++)
        {
            // ympäröivien pikselien keskiarvo
            c1 = buffer[x+1][y];
            c2 = buffer[x-1][y];
            c3 = buffer[x][y+1];
            c4 = buffer[x][y-1];

            cfr = (c1 + c2 + c3 + c4) / 4;

            // väri kylmennys kartasta
            Uint32 c;
            if (y - cooloffset > 0)
                c = getpixel(cooler, x, y - cooloffset);
            else
                c = getpixel(cooler, x, cooloffset - y);

            // otetaan talteen kylmennyskartan punaväri (8 ylintä bittiä; väri on 24 bittinen)
            cfr -= ((c >> 16) & 0xff);
            if (cfr < 0) cfr = 0;

            // piirretään pehmennetty ja kylmennetty pikseli ylöspäin, jotta saadaan liekit menemään ylöspäin
            buffer2[x][y-1] = cfr;
        }

        // pyyhitään alkuperäinen kuva. Tämän voi tehdä tai jättää tekemättä oman maun mukaan.
    for (int x=0;x<=kuvadatapituus;x++)
        {
            buffer[kuvadata[x].x][kuvadata[x].y] = 1;
        }

        // piirretään ruudulle
    for (int x=1;x<SCREENWIDTH-2;x++)
        for (int y=1;y<SCREENHEIGHT-2;y++)
            {
                putpixel(surface, x,y, paletti[buffer2[x][y]]); // 255 - arvo siksi, että sähläsin paletin kanssa ja tein sen väärinpäin.


                //vaihdetaan puskurit keskenään.
                buffer[x][y] = buffer2[x][y];
            }

    // kylmennyskarttaa shiftataan ylös
    cooloffset += 3;
    if (cooloffset >= SCREENHEIGHT) cooloffset = 0;

    // poistetaan lukitus
    if ( SDL_MUSTLOCK(surface) ) {
        SDL_UnlockSurface(surface);
    }

    //päivitä pinta
    SDL_UpdateRect(surface, 0, 0, 0, 0);
}

int main(int argc, char* argv[])
{

  // precalcaa sini ja kosini taulut
  for (int i=0;i<=360;i++)
  {
    costable[i] = cos(i * (3.14159/180));
    sintable[i] = sin(i * (3.14159/180));
  }

  particleinit(); // alusta partikkelit

  //initialize systems
  SDL_Init(SDL_INIT_VIDEO);
  //set our at exit function
  atexit(SDL_Quit);
  //create a window
  SDL_Surface* pSurface = SDL_SetVideoMode ( SCREENWIDTH, SCREENHEIGHT, SCREENBPP, SCREENFLAGS );

  // ladataan kylmennyskartta
  cooler = SDL_LoadBMP("cooler.bmp");

  // ladataan poltettava kuvio
  SDL_Surface *shape = SDL_LoadBMP("shape.bmp");
  for (int x=1;x<SCREENWIDTH-1;x++)
        for (int y=1;y<SCREENHEIGHT-1;y++)
        {    if (getpixel(shape, x,y) == 0)    // jos väri musta -> polta se
            {
                kuvadata[kuvadatapituus].vari = 255;
                kuvadata[kuvadatapituus].x = x;
                kuvadata[kuvadatapituus].y = y;
                kuvadatapituus += 1;
            }
        }

  // normi sdl-looppi
  SDL_Event event;
  for (;;)
  {
    if ( SDL_PollEvent ( &event ) )
    {
      if ( event.type == SDL_QUIT ) break;
    }
    DrawScene(pSurface, &event);

  }

  // vapautellaan
  SDL_FreeSurface(cooler);
  SDL_FreeSurface(shape);
  SDL_FreeSurface(pSurface);

  return(0);
}

Bill Keltanen [15.08.2004 15:16:46]

#

Tosi hieno! Pro oot (vaikket sitä aina myönnä ;) en ite osais tehä)

Heikki [15.08.2004 15:28:35]

#

Taitaa kooditagi vähän bugittaa ainakin Operalla... Koodin loppuosasta puuttuu väritys.

kaviaari [15.08.2004 16:02:19]

#

Aika... sottanen voisit vähän siistiä muuten hyvä.

sooda [15.08.2004 16:47:15]

#

Voot toot. Hieno ku mikä! Kooditagien väritys tosiaan loppuu tossa DrawScenesä muutaman ekan rivin jälkeen.

Metabolix [17.08.2004 16:24:20]

#

Jostakin syystä tuo valmis ohjelma suorittaa ennen pitkää virheen: Virhe muistipaikassa ??: muisti ei voi olla "written".

peki [17.08.2004 19:47:34]

#

Joo. Vika on todennäköisesti siinä, että koodi kirjoittaa taulukon rajojen ulkopuolelle jossain vaiheessa. Ohjelman uudelleen käynnistäminen korjaa ongelman.

thefox [17.08.2004 22:34:37]

#

Kaikki kohdat (taitaa olla ainakin pari) tyyliin "for (int i=0;i<=PARTIKKELEJA;i++)" tulisi olla muodossa "for (int i=0;i<PARTIKKELEJA;i++)" muuten ohjelma kirjoittelee minne sattuu.

peki [18.08.2004 13:24:40]

#

Korjasin nuo kohdat koodista. Exeä en kuitenkaan ole päivittänyt. Efektin demoamiseen se käy, vaikka välillä kaatuileekin. :f

Edit: Exekin on nyt sitten päivitetty..

aloitteleva [24.06.2005 02:05:25]

#

Toi antaa varmaa 300 errorii

Puhveli [08.08.2005 19:04:07]

#

Kaikki kääntäjät eivät vissiin ole tuon _fastcallin kanssa kaveria. Pitääpä koettaa viritellä :p


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta