1 static struct flaretype 2 { 3 int type; /* flaretex index, 0..5, -1 for 6+random shine */ 4 float loc; /* postion on axis */ 5 float scale; /* texture scaling */ 6 uchar alpha; /* color alpha */ 7 } flaretypes[] = 8 { 9 {2, 1.30f, 0.04f, 153}, //flares 10 {3, 1.00f, 0.10f, 102}, 11 {1, 0.50f, 0.20f, 77}, 12 {3, 0.20f, 0.05f, 77}, 13 {0, 0.00f, 0.04f, 77}, 14 {5, -0.25f, 0.07f, 127}, 15 {5, -0.40f, 0.02f, 153}, 16 {5, -0.60f, 0.04f, 102}, 17 {5, -1.00f, 0.03f, 51}, 18 {-1, 1.00f, 0.30f, 255}, //shine - red, green, blue 19 {-2, 1.00f, 0.20f, 255}, 20 {-3, 1.00f, 0.25f, 255} 21 }; 22 23 struct flare 24 { 25 vec o, center; 26 float size; 27 bvec color; 28 int sparkle; // 0 = off, 1 = sparkles and flares, 2 = only sparkles 29 }; 30 31 VAR(IDF_PERSIST, flarelights, 0, 3, 15); // 0 = off, &1 = defined suns, &2 = defined lights, &4 = all suns, &8 = all lights 32 VAR(IDF_PERSIST, flarecutoff, 0, 1000, VAR_MAX); 33 VAR(IDF_PERSIST, flaresize, 1, 100, VAR_MAX); 34 VAR(IDF_PERSIST, flaresundist, 1, 4096, VAR_MAX); 35 VAR(IDF_PERSIST, flareshine, 1, 50, VAR_MAX); 36 FVAR(IDF_PERSIST, flareblend, 0, 0.5f, 1); 37 FVAR(IDF_PERSIST, flareadjust, 0, 0.7f, 1); 38 39 struct flarerenderer : partrenderer 40 { 41 int maxflares, numflares; 42 unsigned int shinetime; 43 flare *flares; 44 flarerendererflarerenderer45 flarerenderer(const char *texname, int maxflares) 46 : partrenderer(texname, 3, PT_FLARE|PT_SHADER), maxflares(maxflares), numflares(0), shinetime(0) 47 { 48 flares = new flare[maxflares]; 49 } ~flarerendererflarerenderer50 ~flarerenderer() 51 { 52 delete[] flares; 53 } 54 resetflarerenderer55 void reset() 56 { 57 numflares = 0; 58 } 59 newflareflarerenderer60 void newflare(const vec &o, const vec ¢er, uchar r, uchar g, uchar b, float mod, float size, bool sun, int sparkle) 61 { 62 if(numflares >= maxflares) return; 63 vec target; //occlusion check (neccessary as depth testing is turned off) 64 if(!raycubelos(o, camera1->o, target)) return; 65 flare &f = flares[numflares++]; 66 f.o = o; 67 f.center = center; 68 f.size = size; 69 f.color = bvec(uchar(r*mod), uchar(g*mod), uchar(b*mod)); 70 f.sparkle = sparkle; 71 } 72 generateflarerenderer73 bool generate(const vec &o, vec &flaredir, float &mod, float &size, bool sun, float radius) 74 { 75 flaredir = vec(o).sub(camera1->o); 76 if(sun) //fixed size 77 { 78 mod = 1.0f; 79 size = flaresundist*flaresize/100.0f; 80 } 81 else 82 { 83 float len = flaredir.magnitude(); 84 if(len > radius) return false; 85 mod = (radius-len)/radius; 86 size = flaresize/10.0f; 87 } 88 return isvisiblesphere(size, o) <= (sun ? VFC_FOGGED : VFC_FULL_VISIBLE); 89 } 90 addflareflarerenderer91 void addflare(const vec &o, uchar r, uchar g, uchar b, bool sun, bool project, int sparkle) 92 { 93 //frustrum + fog check 94 //find closest point between camera line of sight and flare pos 95 vec flaredir; 96 float mod = 0, size = 0; 97 if(generate(o, flaredir, mod, size, sun || project, flarecutoff)) 98 newflare(o, vec(camdir).mul(flaredir.dot(camdir)).add(camera1->o), r, g, b, mod, size, sun, sparkle); 99 } 100 setupflaresflarerenderer101 void setupflares() 102 { 103 numflares = 0; //regenerate flarelist each frame 104 shinetime = lastmillis/flareshine; 105 } 106 drawflaresflarerenderer107 void drawflares() 108 { 109 if(flarelights) 110 { 111 const vector<extentity *> &ents = entities::getents(); 112 int numents = entities::lastent(ET_SUNLIGHT); 113 loopi(numents) 114 { 115 extentity &e = *ents[i]; 116 bool sun = false, project = false; 117 int sparkle = 0; 118 vec o = e.o; 119 uchar r = 255, g = 255, b = 255; 120 float scale = 1.f; 121 switch(e.type) 122 { 123 case ET_LIGHT: 124 if(flarelights&8 || (flarelights&2 && e.attrs[4])) 125 { 126 if(!e.attrs[0] || e.attrs[4]&1) sun = true; 127 if(!e.attrs[0] || e.attrs[4]&2) sparkle = sun ? 1 : 2; 128 r = e.attrs[1]; 129 g = e.attrs[2]; 130 b = e.attrs[3]; 131 if(e.attrs[5] > 0) scale = e.attrs[5]/100.f; 132 break; 133 } 134 else continue; 135 case ET_SUNLIGHT: 136 if(flarelights&4 || (flarelights&1 && e.attrs[6])) 137 { 138 if(!e.attrs[6] || e.attrs[6]&1) sun = true; 139 if(!e.attrs[6] || e.attrs[6]&2) sparkle = sun ? 1 : 2; 140 r = e.attrs[2]; 141 g = e.attrs[3]; 142 b = e.attrs[4]; 143 o = vec(camera1->o).add(vec(e.attrs[0]*RAD, (e.attrs[1]+90)*RAD).mul(getworldsize()*2)); 144 project = true; 145 if(e.attrs[7] > 0) scale = e.attrs[7]/100.f; 146 break; 147 } 148 else continue; 149 default: continue; 150 } 151 vec flaredir; 152 float mod = 0, size = 0, radius = project ? 0.f : e.attrs[0]*flaresize/100.f; 153 if(generate(o, flaredir, mod, size, sun || project, radius)) 154 newflare(o, vec(camdir).mul(flaredir.dot(camdir)).add(camera1->o), r, g, b, mod, size*scale, sun, sparkle); 155 } 156 } 157 } 158 countflarerenderer159 int count() 160 { 161 return numflares; 162 } 163 hasworkflarerenderer164 bool haswork() 165 { 166 return (numflares != 0) && !glaring && !reflecting && !refracting; 167 } 168 renderflarerenderer169 void render() 170 { 171 textureshader->set(); 172 glDisable(GL_DEPTH_TEST); 173 preload(); 174 if(tex) glBindTexture(GL_TEXTURE_2D, tex->id); 175 gle::defattrib(gle::ATTRIB_VERTEX, 3, GL_FLOAT); 176 gle::defattrib(gle::ATTRIB_TEXCOORD0, 2, GL_FLOAT); 177 gle::defattrib(gle::ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE); 178 gle::begin(GL_QUADS); 179 loopi(numflares) 180 { 181 const flare &f = flares[i]; 182 float blend = flareblend; 183 vec center = f.center, axis = vec(f.o).sub(center); 184 if(flareadjust > 0) 185 { 186 float yaw, pitch; 187 vec dir = vec(f.o).sub(camera1->o).normalize(); 188 vectoyawpitch(dir, yaw, pitch); 189 yaw -= camera1->yaw; 190 while(yaw < -180.0f) yaw += 360.0f; 191 while(yaw >= 180.0f) yaw -= 360.0f; 192 if(yaw < 0) yaw = -yaw; 193 blend *= 1-min(yaw/(curfov*0.5f)*flareadjust, 1.f); 194 pitch -= camera1->pitch; 195 while(pitch < -180.0f) pitch += 360.0f; 196 while(pitch >= 180.0f) pitch -= 360.0f; 197 if(pitch < 0) pitch = -pitch; 198 blend *= 1-min(pitch/(fovy*0.5f)*flareadjust, 1.f); 199 } 200 bvec4 color(f.color, 255); 201 loopj(f.sparkle ? (f.sparkle != 2 ? 12 : 3) : 9) 202 { 203 int q = f.sparkle != 2 ? j : j+9; 204 const flaretype &ft = flaretypes[q]; 205 vec o = vec(axis).mul(ft.loc).add(center); 206 float sz = ft.scale*f.size; 207 int tex = ft.type; 208 if(ft.type < 0) //sparkles - always done last 209 { 210 tex = 6+((shinetime+1)%10); 211 color.r = 0; 212 color.g = 0; 213 color.b = 0; 214 color[-ft.type-1] = f.color[-ft.type-1]; //only want a single channel 215 } 216 color.a = uchar(ceilf(ft.alpha*blend)); 217 const float tsz = 0.25f; //flares are aranged in 4x4 grid 218 float tx = tsz*(tex&0x03), ty = tsz*((tex>>2)&0x03); 219 gle::attribf(o.x+(-camright.x+camup.x)*sz, o.y+(-camright.y+camup.y)*sz, o.z+(-camright.z+camup.z)*sz); 220 gle::attribf(tx, ty+tsz); 221 gle::attrib(color); 222 gle::attribf(o.x+( camright.x+camup.x)*sz, o.y+( camright.y+camup.y)*sz, o.z+( camright.z+camup.z)*sz); 223 gle::attribf(tx+tsz, ty+tsz); 224 gle::attrib(color); 225 gle::attribf(o.x+( camright.x-camup.x)*sz, o.y+( camright.y-camup.y)*sz, o.z+( camright.z-camup.z)*sz); 226 gle::attribf(tx+tsz, ty); 227 gle::attrib(color); 228 gle::attribf(o.x+(-camright.x-camup.x)*sz, o.y+(-camright.y-camup.y)*sz, o.z+(-camright.z-camup.z)*sz); 229 gle::attribf(tx, ty); 230 gle::attrib(color); 231 } 232 } 233 gle::end(); 234 glEnable(GL_DEPTH_TEST); 235 } 236 237 //square per round hole - use addflare(..) instead 238 particle *addpart(const vec &o, const vec &d, int fade, int color, float size, float blend = 1, int grav = 0, int collide = 0, physent *pl = NULL) { return NULL; } 239 }; 240 static flarerenderer flares("<grey>particles/lensflares", 128); 241