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 bool sparkle; 29 }; 30 31 VAR(flarelights, 0, 0, 1); 32 VARP(flarecutoff, 0, 1000, 10000); 33 VARP(flaresize, 20, 100, 500); 34 35 struct flarerenderer : partrenderer 36 { 37 int maxflares, numflares; 38 unsigned int shinetime; 39 flare *flares; 40 flarerendererflarerenderer41 flarerenderer(const char *texname, int maxflares) 42 : partrenderer(texname, 3, PT_FLARE|PT_SHADER), maxflares(maxflares), numflares(0), shinetime(0) 43 { 44 flares = new flare[maxflares]; 45 } ~flarerendererflarerenderer46 ~flarerenderer() 47 { 48 delete[] flares; 49 } 50 resetflarerenderer51 void reset() 52 { 53 numflares = 0; 54 } 55 newflareflarerenderer56 void newflare(vec &o, const vec ¢er, uchar r, uchar g, uchar b, float mod, float size, bool sun, bool sparkle) 57 { 58 if(numflares >= maxflares) return; 59 vec target; //occlusion check (neccessary as depth testing is turned off) 60 if(!raycubelos(o, camera1->o, target)) return; 61 flare &f = flares[numflares++]; 62 f.o = o; 63 f.center = center; 64 f.size = size; 65 f.color = bvec(uchar(r*mod), uchar(g*mod), uchar(b*mod)); 66 f.sparkle = sparkle; 67 } 68 addflareflarerenderer69 void addflare(vec &o, uchar r, uchar g, uchar b, bool sun, bool sparkle) 70 { 71 //frustrum + fog check 72 if(isvisiblesphere(0.0f, o) > (sun?VFC_FOGGED:VFC_FULL_VISIBLE)) return; 73 //find closest point between camera line of sight and flare pos 74 vec flaredir = vec(o).sub(camera1->o); 75 vec center = vec(camdir).mul(flaredir.dot(camdir)).add(camera1->o); 76 float mod, size; 77 if(sun) //fixed size 78 { 79 mod = 1.0; 80 size = flaredir.magnitude() * flaresize / 100.0f; 81 } 82 else 83 { 84 mod = (flarecutoff-vec(o).sub(center).squaredlen())/flarecutoff; 85 if(mod < 0.0f) return; 86 size = flaresize / 5.0f; 87 } 88 newflare(o, center, r, g, b, mod, size, sun, sparkle); 89 } 90 makelightflaresflarerenderer91 void makelightflares() 92 { 93 numflares = 0; //regenerate flarelist each frame 94 shinetime = lastmillis/10; 95 96 if(editmode || !flarelights) return; 97 98 const vector<extentity *> &ents = entities::getents(); 99 extern const vector<int> &checklightcache(int x, int y); 100 const vector<int> &lights = checklightcache(int(camera1->o.x), int(camera1->o.y)); 101 loopv(lights) 102 { 103 entity &e = *ents[lights[i]]; 104 if(e.type != ET_LIGHT) continue; 105 bool sun = (e.attr1==0); 106 float radius = float(e.attr1); 107 vec flaredir = vec(e.o).sub(camera1->o); 108 float len = flaredir.magnitude(); 109 if(!sun && (len > radius)) continue; 110 if(isvisiblesphere(0.0f, e.o) > (sun?VFC_FOGGED:VFC_FULL_VISIBLE)) continue; 111 vec center = vec(camdir).mul(flaredir.dot(camdir)).add(camera1->o); 112 float mod, size; 113 if(sun) //fixed size 114 { 115 mod = 1.0; 116 size = len * flaresize / 100.0f; 117 } 118 else 119 { 120 mod = (radius-len)/radius; 121 size = flaresize / 5.0f; 122 } 123 newflare(e.o, center, e.attr2, e.attr3, e.attr4, mod, size, sun, sun); 124 } 125 } 126 countflarerenderer127 int count() 128 { 129 return numflares; 130 } 131 hasworkflarerenderer132 bool haswork() 133 { 134 return (numflares != 0) && !glaring && !reflecting && !refracting; 135 } 136 renderflarerenderer137 void render() 138 { 139 textureshader->set(); 140 glDisable(GL_DEPTH_TEST); 141 if(!tex) tex = textureload(texname); 142 glBindTexture(GL_TEXTURE_2D, tex->id); 143 gle::defattrib(gle::ATTRIB_VERTEX, 3, GL_FLOAT); 144 gle::defattrib(gle::ATTRIB_TEXCOORD0, 2, GL_FLOAT); 145 gle::defattrib(gle::ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE); 146 gle::begin(GL_QUADS); 147 loopi(numflares) 148 { 149 const flare &f = flares[i]; 150 vec center = f.center; 151 vec axis = vec(f.o).sub(center); 152 bvec4 color(f.color, 255); 153 loopj(f.sparkle?12:9) 154 { 155 const flaretype &ft = flaretypes[j]; 156 vec o = vec(axis).mul(ft.loc).add(center); 157 float sz = ft.scale * f.size; 158 int tex = ft.type; 159 if(ft.type < 0) //sparkles - always done last 160 { 161 shinetime = (shinetime + 1) % 10; 162 tex = 6+shinetime; 163 color.r = 0; 164 color.g = 0; 165 color.b = 0; 166 color[-ft.type-1] = f.color[-ft.type-1]; //only want a single channel 167 } 168 color.a = ft.alpha; 169 const float tsz = 0.25; //flares are aranged in 4x4 grid 170 float tx = tsz*(tex&0x03), ty = tsz*((tex>>2)&0x03); 171 gle::attribf(o.x+(-camright.x+camup.x)*sz, o.y+(-camright.y+camup.y)*sz, o.z+(-camright.z+camup.z)*sz); 172 gle::attribf(tx, ty+tsz); 173 gle::attrib(color); 174 gle::attribf(o.x+( camright.x+camup.x)*sz, o.y+( camright.y+camup.y)*sz, o.z+( camright.z+camup.z)*sz); 175 gle::attribf(tx+tsz, ty+tsz); 176 gle::attrib(color); 177 gle::attribf(o.x+( camright.x-camup.x)*sz, o.y+( camright.y-camup.y)*sz, o.z+( camright.z-camup.z)*sz); 178 gle::attribf(tx+tsz, ty); 179 gle::attrib(color); 180 gle::attribf(o.x+(-camright.x-camup.x)*sz, o.y+(-camright.y-camup.y)*sz, o.z+(-camright.z-camup.z)*sz); 181 gle::attribf(tx, ty); 182 gle::attrib(color); 183 } 184 } 185 gle::end(); 186 glEnable(GL_DEPTH_TEST); 187 } 188 189 //square per round hole - use addflare(..) instead 190 particle *addpart(const vec &o, const vec &d, int fade, int color, float size, int gravity = 0) { return NULL; } 191 }; 192 static flarerenderer flares("<grey>packages/particles/lensflares.png", 64); 193 194