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.