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); }
Tosi hieno! Pro oot (vaikket sitä aina myönnä ;) en ite osais tehä)
Taitaa kooditagi vähän bugittaa ainakin Operalla... Koodin loppuosasta puuttuu väritys.
Aika... sottanen voisit vähän siistiä muuten hyvä.
Voot toot. Hieno ku mikä! Kooditagien väritys tosiaan loppuu tossa DrawScenesä muutaman ekan rivin jälkeen.
Jostakin syystä tuo valmis ohjelma suorittaa ennen pitkää virheen: Virhe muistipaikassa ??: muisti ei voi olla "written".
Joo. Vika on todennäköisesti siinä, että koodi kirjoittaa taulukon rajojen ulkopuolelle jossain vaiheessa. Ohjelman uudelleen käynnistäminen korjaa ongelman.
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.
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..
Toi antaa varmaa 300 errorii
Kaikki kääntäjät eivät vissiin ole tuon _fastcallin kanssa kaveria. Pitääpä koettaa viritellä :p
Aihe on jo aika vanha, joten et voi enää vastata siihen.