From 29efbcaa3a6d461dbe39b6e2fd8d29aeb537165b Mon Sep 17 00:00:00 2001 From: Simon Robertshaw Date: Thu, 20 Oct 2011 00:34:31 +0100 Subject: [PATCH] Glow, Fire, Smoke, blob and flat particle effects in OpenGL --- src/elements/fire.c | 8 +- src/elements/lava.c | 4 +- src/elements/neut.c | 2 +- src/elements/newgraphics.c | 26 +-- src/elements/plsm.c | 8 +- src/graphics.c | 322 ++++++++++++++++++++++++++++++++++--- src/main.c | 3 +- 7 files changed, 327 insertions(+), 46 deletions(-) diff --git a/src/elements/fire.c b/src/elements/fire.c index 375010ae2..391c743b2 100644 --- a/src/elements/fire.c +++ b/src/elements/fire.c @@ -8,12 +8,12 @@ int graphics_FIRE(GRAPHICS_FUNC_ARGS) *colb = (unsigned char)flm_data[caddress+2]; *firea = 255; - *firer = *colr/8; - *fireg = *colg/8; - *fireb = *colb/8; + *firer = *colr; + *fireg = *colg; + *fireb = *colb; *pixel_mode = PMODE_NONE; //Clear default, don't draw pixel *pixel_mode |= FIRE_ADD; //Returning 0 means dynamic, do not cache return 0; -} \ No newline at end of file +} diff --git a/src/elements/lava.c b/src/elements/lava.c index 873b1750e..a748cf708 100644 --- a/src/elements/lava.c +++ b/src/elements/lava.c @@ -8,7 +8,7 @@ int graphics_LAVA(GRAPHICS_FUNC_ARGS) if (*colr>255) *colr = 255; if (*colg>192) *colg = 192; if (*colb>128) *colb = 128; - *firea = 5; + *firea = 40; *firer = *colr; *fireg = *colg; *fireb = *colb; @@ -16,4 +16,4 @@ int graphics_LAVA(GRAPHICS_FUNC_ARGS) *pixel_mode |= PMODE_BLUR; //Returning 0 means dynamic, do not cache return 0; -} \ No newline at end of file +} diff --git a/src/elements/neut.c b/src/elements/neut.c index 0dfc2b171..78552d5c3 100644 --- a/src/elements/neut.c +++ b/src/elements/neut.c @@ -135,7 +135,7 @@ int update_NEUT(UPDATE_FUNC_ARGS) { int graphics_NEUT(GRAPHICS_FUNC_ARGS) { - *firea = 15; + *firea = 120; *firer = 10; *fireg = 80; *fireb = 120; diff --git a/src/elements/newgraphics.c b/src/elements/newgraphics.c index 21d733467..6f941e005 100644 --- a/src/elements/newgraphics.c +++ b/src/elements/newgraphics.c @@ -114,7 +114,7 @@ int graphics_DUST(GRAPHICS_FUNC_ARGS) *colg = (a*((parts[i].dcolour>>8)&0xFF) + (255-a)**colg) >> 8; *colb = (a*((parts[i].dcolour)&0xFF) + (255-a)**colb) >> 8; } - *firea = 64; + *firea = 255; *firer = *colr; *fireg = *colg; *fireb = *colb; @@ -165,7 +165,7 @@ int graphics_WIFI(GRAPHICS_FUNC_ARGS) } int graphics_PRTI(GRAPHICS_FUNC_ARGS) { - *firea = 1; + *firea = 8; *firer = 255; *fireg = 0; *fireb = 0; @@ -176,7 +176,7 @@ int graphics_PRTI(GRAPHICS_FUNC_ARGS) } int graphics_PRTO(GRAPHICS_FUNC_ARGS) { - *firea = 1; + *firea = 8; *firer = 0; *fireg = 0; *fireb = 255; @@ -204,9 +204,9 @@ int graphics_BIZR(GRAPHICS_FUNC_ARGS) //BIZR, BIZRG, BIZRS if(fabs(parts[i].vx)+fabs(parts[i].vy)>0) { *firea = 255; - *fireg = *colg/40 * fabs(parts[i].vx)+fabs(parts[i].vy); - *fireb = *colb/40 * fabs(parts[i].vx)+fabs(parts[i].vy); - *firer = *colr/40 * fabs(parts[i].vx)+fabs(parts[i].vy); + *fireg = *colg/5 * fabs(parts[i].vx)+fabs(parts[i].vy); + *fireb = *colb/5 * fabs(parts[i].vx)+fabs(parts[i].vy); + *firer = *colr/5 * fabs(parts[i].vx)+fabs(parts[i].vy); *pixel_mode |= FIRE_ADD; } return 0; @@ -374,7 +374,7 @@ int graphics_SWCH(GRAPHICS_FUNC_ARGS) } int graphics_THDR(GRAPHICS_FUNC_ARGS) { - *firea = 20; + *firea = 160; *fireg = 192; *fireb = 255; *firer = 144; @@ -480,9 +480,9 @@ int graphics_HFLM(GRAPHICS_FUNC_ARGS) *colb = (unsigned char)hflm_data[caddress+2]; *firea = 255; - *firer = *colr/8; - *fireg = *colg/8; - *fireb = *colb/8; + *firer = *colr; + *fireg = *colg; + *fireb = *colb; *pixel_mode = PMODE_NONE; //Clear default, don't draw pixel *pixel_mode |= FIRE_ADD; @@ -505,9 +505,9 @@ int graphics_FIRW(GRAPHICS_FUNC_ARGS) } *firea = 255; - *firer = *colr/8; - *fireg = *colg/8; - *fireb = *colb/8; + *firer = *colr; + *fireg = *colg; + *fireb = *colb; *pixel_mode = PMODE_NONE; //Clear default, don't draw pixel *pixel_mode |= FIRE_ADD; diff --git a/src/elements/plsm.c b/src/elements/plsm.c index e7906af71..3bab69377 100644 --- a/src/elements/plsm.c +++ b/src/elements/plsm.c @@ -8,12 +8,12 @@ int graphics_PLSM(GRAPHICS_FUNC_ARGS) *colb = (unsigned char)plasma_data[caddress+2]; *firea = 255; - *firer = *colr/8; - *fireg = *colg/8; - *fireb = *colb/8; + *firer = *colr; + *fireg = *colg; + *fireb = *colb; *pixel_mode = PMODE_NONE; //Clear default, don't draw pixel *pixel_mode |= FIRE_ADD; //Returning 0 means dynamic, do not cache return 0; -} \ No newline at end of file +} diff --git a/src/graphics.c b/src/graphics.c index 3488d9596..0b77fa5c0 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -26,7 +26,7 @@ unsigned cmode = CM_FIRE; SDL_Surface *sdl_scrn; int sdl_scale = 1; -GLuint vidBuf; +GLuint vidBuf, fireAlpha, glowAlpha, fireProg; int sandcolour_r = 0; int sandcolour_g = 0; @@ -299,9 +299,9 @@ void ogl_blit(int x, int y, int w, int h, pixel *src, int pitch, int scale) //glDrawPixels(w,h,GL_BGRA,GL_UNSIGNED_BYTE,src); //Why does this still think it's ABGR? glEnable( GL_TEXTURE_2D ); glBindTexture(GL_TEXTURE_2D, vidBuf); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, XRES+BARSIZE, YRES+MENUSIZE, GL_BGRA, GL_UNSIGNED_BYTE, src); - - glBegin(GL_QUADS); + glBegin(GL_QUADS); glTexCoord2d(1, 0); glVertex3f(XRES+BARSIZE, YRES+MENUSIZE, 1.0); glTexCoord2d(0, 0); @@ -1400,15 +1400,30 @@ void xor_rect(pixel *vid, int x, int y, int w, int h) //New function for drawing particles #ifdef OGLR -GLuint va[(YRES*XRES)*2]; -GLfloat ca[(YRES*XRES)*3]; +GLuint fireV[(YRES*XRES)*2]; +GLfloat fireC[(YRES*XRES)*4]; +GLuint smokeV[(YRES*XRES)*2]; +GLfloat smokeC[(YRES*XRES)*4]; +GLuint blobV[(YRES*XRES)*2]; +GLfloat blobC[(YRES*XRES)*4]; +GLuint blurV[(YRES*XRES)*2]; +GLfloat blurC[(YRES*XRES)*4]; +GLuint glowV[(YRES*XRES)*2]; +GLfloat glowC[(YRES*XRES)*4]; +GLuint flatV[(YRES*XRES)*2]; +GLfloat flatC[(YRES*XRES)*4]; #endif void render_parts(pixel *vid) { //TODO: Replace cmode with a set of flags int deca, decr, decg, decb, colr, colg, colb, firea, firer, fireg, fireb, pixel_mode, i, t, nx, ny, x, y, caddress; #ifdef OGLR - int cv = 0, cc = 0, pc = 0; + int cfireV = 0, cfireC = 0, cfire = 0; + int csmokeV = 0, csmokeC = 0, csmoke = 0; + int cblobV = 0, cblobC = 0, cblob = 0; + int cblurV = 0, cblurC = 0, cblur = 0; + int cglowV = 0, cglowC = 0, cglow = 0; + int cflatV = 0, cflatC = 0, cflat = 0; #endif float gradv, flicker; for(i = 0; i<=parts_lastActiveIndex; i++) { @@ -1470,14 +1485,15 @@ void render_parts(pixel *vid) if(cmode == CM_NOTHING) { #ifdef OGLR - va[cv++] = nx; - va[cv++] = ny; - ca[cc++] = ((float)colr)/255.0f; - ca[cc++] = ((float)colg)/255.0f; - ca[cc++] = ((float)colb)/255.0f; - pc++; + flatV[cflatV++] = nx; + flatV[cflatV++] = ny; + flatC[cflatC++] = ((float)colr)/255.0f; + flatC[cflatC++] = ((float)colg)/255.0f; + flatC[cflatC++] = ((float)colb)/255.0f; + flatC[cflatC++] = 1.0f; + cflat++; #else - vid[ny*(XRES+BARSIZE)+nx] = PIXRGB(colr,colg,colb); + vid[ny*(XRES+BARSIZE)+nx] = PIXRGB(colr,colg,colb); #endif } else @@ -1528,10 +1544,29 @@ void render_parts(pixel *vid) //Pixel rendering if(pixel_mode & PMODE_FLAT) { +#ifdef OGLR + flatV[cflatV++] = nx; + flatV[cflatV++] = ny; + flatC[cflatC++] = ((float)colr)/255.0f; + flatC[cflatC++] = ((float)colg)/255.0f; + flatC[cflatC++] = ((float)colb)/255.0f; + flatC[cflatC++] = 1.0f; + cflat++; +#else vid[ny*(XRES+BARSIZE)+nx] = PIXRGB(colr,colg,colb); +#endif } if(pixel_mode & PMODE_BLOB) { +#ifdef OGLR + blobV[cblobV++] = nx; + blobV[cblobV++] = ny; + blobC[cblobC++] = ((float)colr)/255.0f; + blobC[cblobC++] = ((float)colg)/255.0f; + blobC[cblobC++] = ((float)colb)/255.0f; + blobC[cblobC++] = 1.0f; + cblob++; +#else blendpixel(vid, nx+1, ny, colr, colg, colb, 223); blendpixel(vid, nx-1, ny, colr, colg, colb, 223); blendpixel(vid, nx, ny+1, colr, colg, colb, 223); @@ -1541,9 +1576,19 @@ void render_parts(pixel *vid) blendpixel(vid, nx-1, ny-1, colr, colg, colb, 112); blendpixel(vid, nx+1, ny+1, colr, colg, colb, 112); blendpixel(vid, nx-1, ny+1, colr, colg, colb, 112); +#endif } if(pixel_mode & PMODE_GLOW) { +#ifdef OGLR + glowV[cglowV++] = nx; + glowV[cglowV++] = ny; + glowC[cglowC++] = ((float)colr)/255.0f; + glowC[cglowC++] = ((float)colg)/255.0f; + glowC[cglowC++] = ((float)colb)/255.0f; + glowC[cglowC++] = 1.0f; + cglow++; +#else addpixel(vid, nx, ny, colr, colg, colb, 192); addpixel(vid, nx+1, ny, colr, colg, colb, 96); addpixel(vid, nx-1, ny, colr, colg, colb, 96); @@ -1564,9 +1609,19 @@ void render_parts(pixel *vid) addpixel(vid, nx-x, ny-y, colr, colg, colb, 5); } } +#endif } if(pixel_mode & PMODE_BLUR) { +#ifdef OGLR + blurV[cblurV++] = nx; + blurV[cblurV++] = ny; + blurC[cblurC++] = ((float)colr)/255.0f; + blurC[cblurC++] = ((float)colg)/255.0f; + blurC[cblurC++] = ((float)colb)/255.0f; + blurC[cblurC++] = 1.0f; + cblur++; +#else for (x=-3; x<4; x++) { for (y=-3; y<4; y++) @@ -1579,6 +1634,7 @@ void render_parts(pixel *vid) blendpixel(vid, x+nx, y+ny, colr, colg, colb, 10); } } +#endif } if(pixel_mode & PMODE_SPARK) { @@ -1640,6 +1696,16 @@ void render_parts(pixel *vid) //Fire effects if(firea && (pixel_mode & FIRE_BLEND)) { +#ifdef OGLR + smokeV[csmokeV++] = nx; + smokeV[csmokeV++] = ny; + smokeC[csmokeC++] = ((float)firer)/255.0f; + smokeC[csmokeC++] = ((float)fireg)/255.0f; + smokeC[csmokeC++] = ((float)fireb)/255.0f; + smokeC[csmokeC++] = ((float)firea)/255.0f; + csmoke++; +#else + firea /= 8; if(cmode==CM_FIRE || cmode==CM_BLOB || cmode==CM_FANCY) { fire_r[ny/CELL][nx/CELL] = (firea*firer + (255-firea)*fire_r[ny/CELL][nx/CELL]) >> 8; @@ -1660,9 +1726,20 @@ void render_parts(pixel *vid) } } } +#endif } if(firea && (pixel_mode & FIRE_ADD)) { +#ifdef OGLR + fireV[cfireV++] = nx; + fireV[cfireV++] = ny; + fireC[cfireC++] = ((float)firer)/255.0f; + fireC[cfireC++] = ((float)fireg)/255.0f; + fireC[cfireC++] = ((float)fireb)/255.0f; + fireC[cfireC++] = ((float)firea)/255.0f; + cfire++; +#else + firea /= 8; if(cmode==CM_FIRE || cmode==CM_BLOB || cmode==CM_FANCY) { firer = ((firea*firer) >> 8) + fire_r[ny/CELL][nx/CELL]; @@ -1693,25 +1770,140 @@ void render_parts(pixel *vid) } } } +#endif } } } } -#ifdef OGLR - glScalef(1,-1,1); +#ifdef OGLR + //Set coord offset + glScalef(1,-1,1); glTranslatef(0, -(YRES+MENUSIZE), 0); + + //Go into array mode glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); - glColorPointer(3, GL_FLOAT, 0, &ca[0]); - glVertexPointer(2, GL_INT, 0, &va[0]); + if(cflat) + { + // -- BEGIN FLAT -- // + //Set point size (size of fire texture) + glPointSize(1.0f); - glDrawArrays(GL_POINTS, 0, pc); + glColorPointer(4, GL_FLOAT, 0, &flatC[0]); + glVertexPointer(2, GL_INT, 0, &flatV[0]); + + glDrawArrays(GL_POINTS, 0, cflat); + + //Clear some stuff we set + // -- END FLAT -- // + } + + if(cglow) + { + // -- BEGIN GLOW -- // + //Start and prepare fire program + glEnable(GL_TEXTURE_2D); + glUseProgram(fireProg); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, glowAlpha); + glUniform1i(glGetUniformLocation(fireProg, "fireAlpha"), 0); + + //Make sure we can use texture coords on points + glEnable(GL_POINT_SPRITE); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); + + //Set point size (size of fire texture) + glPointSize(11.0f); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + + glColorPointer(4, GL_FLOAT, 0, &glowC[0]); + glVertexPointer(2, GL_INT, 0, &glowV[0]); + + glDrawArrays(GL_POINTS, 0, cglow); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + //Clear some stuff we set + glDisable(GL_POINT_SPRITE); + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); + glUseProgram(0); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + // -- END GLOW -- // + } + + if(cblob) + { + // -- BEGIN BLOB -- // + glEnable( GL_POINT_SMOOTH ); //Blobs! + glPointSize(2.5f); + + glColorPointer(4, GL_FLOAT, 0, &blobC[0]); + glVertexPointer(2, GL_INT, 0, &blobV[0]); + + glDrawArrays(GL_POINTS, 0, cblob); + + //Clear some stuff we set + glDisable( GL_POINT_SMOOTH ); + // -- END BLOB -- // + } + + if(cfire || csmoke) + { + // -- BEGIN FIRE -- // + //Start and prepare fire program + glEnable(GL_TEXTURE_2D); + glUseProgram(fireProg); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, fireAlpha); + glUniform1i(glGetUniformLocation(fireProg, "fireAlpha"), 0); + + //Make sure we can use texture coords on points + glEnable(GL_POINT_SPRITE); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); + + //Set point size (size of fire texture) + glPointSize(CELL*3); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + + if(cfire) + { + glColorPointer(4, GL_FLOAT, 0, &fireC[0]); + glVertexPointer(2, GL_INT, 0, &fireV[0]); + + glDrawArrays(GL_POINTS, 0, cfire); + } + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if(csmoke) + { + glColorPointer(4, GL_FLOAT, 0, &smokeC[0]); + glVertexPointer(2, GL_INT, 0, &smokeV[0]); + + glDrawArrays(GL_POINTS, 0, csmoke); + } + + //Clear some stuff we set + glDisable(GL_POINT_SPRITE); + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); + glUseProgram(0); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + // -- END FIRE -- // + } glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + + //Reset coords/offset glTranslatef(0, YRES+MENUSIZE, 0); - glScalef(1,-1,1); + glScalef(1,-1,1); #endif } @@ -2208,9 +2400,11 @@ void render_fire(pixel *vid) void prepare_alpha(int size, float intensity) { //TODO: implement size - int x,y,i,j; + int x,y,i,j,c; float multiplier = 255.0f*intensity; float temp[CELL*3][CELL*3]; + float fire_alphaf[CELL*3][CELL*3]; + float glow_alphaf[11][11]; memset(temp, 0, sizeof(temp)); for (x=0; x 7) + continue; + glow_alphaf[c+x][c-y] += 0.02f; + glow_alphaf[c-x][c+y] += 0.02f; + glow_alphaf[c+x][c+y] += 0.02f; + glow_alphaf[c-x][c-y] += 0.02f; + } + } + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, glowAlpha); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 11, 11, GL_ALPHA, GL_FLOAT, glow_alphaf); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); +#endif } pixel *render_packed_rgb(void *image, int width, int height, int cmp_size) @@ -2747,6 +2983,30 @@ int sdl_open(void) glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); + + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &fireAlpha); + glBindTexture(GL_TEXTURE_2D, fireAlpha); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, CELL*3, CELL*3, 0, GL_ALPHA, GL_FLOAT, NULL); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &glowAlpha); + glBindTexture(GL_TEXTURE_2D, glowAlpha); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 11, 11, 0, GL_ALPHA, GL_FLOAT, NULL); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + loadShaders(); #else #ifdef PIX16 if (kiosk_enable) @@ -2781,6 +3041,26 @@ int sdl_open(void) return 1; } +void loadShaders() +{ + GLuint vsize, fsize, vertexShader, fragmentShader; + const char *vertex = file_load("test.vert", &vsize), * fragment = file_load("test.frag", &fsize); + + vertexShader = glCreateShader(GL_VERTEX_SHADER); + fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource( vertexShader, 1, &vertex, &vsize); + glShaderSource( fragmentShader, 1, &fragment, &fsize); + + glCompileShader( vertexShader ); + glCompileShader( fragmentShader ); + + fireProg = glCreateProgram(); + glAttachShader( fireProg, vertexShader ); + glAttachShader( fireProg, fragmentShader ); + glLinkProgram( fireProg ); +} + int draw_debug_info(pixel* vid, int lm, int lx, int ly, int cx, int cy, int line_x, int line_y) { char infobuf[256]; diff --git a/src/main.c b/src/main.c index 8cf827571..bcd0558d4 100644 --- a/src/main.c +++ b/src/main.c @@ -1727,7 +1727,6 @@ int main(int argc, char *argv[]) } make_kernel(); - prepare_alpha(CELL, 1.0f); stamp_init(); @@ -1740,6 +1739,8 @@ int main(int argc, char *argv[]) save_presets(0); http_init(http_proxy_string[0] ? http_proxy_string : NULL); + prepare_alpha(CELL, 1.0f); + if (cpu_check()) { error_ui(vid_buf, 0, "Unsupported CPU. Try another version.");