1 /*
2  *  RenderRasterize_Shader.cpp
3  *  Created by Clemens Unterkofler on 1/20/09.
4  *  for Aleph One
5  *
6  *  http://www.gnu.org/licenses/gpl.html
7  */
8 
9 #include "OGL_Headers.h"
10 
11 #include <iostream>
12 
13 #include "RenderRasterize_Shader.h"
14 
15 #include "lightsource.h"
16 #include "media.h"
17 #include "player.h"
18 #include "weapons.h"
19 #include "AnimatedTextures.h"
20 #include "OGL_Faders.h"
21 #include "OGL_Textures.h"
22 #include "OGL_Shader.h"
23 #include "ChaseCam.h"
24 #include "preferences.h"
25 #include "screen.h"
26 
27 #define MAXIMUM_VERTICES_PER_WORLD_POLYGON (MAXIMUM_VERTICES_PER_POLYGON+4)
28 
29 inline bool FogActive();
30 
31 class Blur {
32 
33 private:
34 	FBOSwapper _swapper;
35 	Shader *_shader_blur;
36 	Shader *_shader_bloom;
37 	GLuint _width;
38 	GLuint _height;
39 
40 public:
41 
Blur(GLuint w,GLuint h,Shader * s_blur,Shader * s_bloom)42 	Blur(GLuint w, GLuint h, Shader* s_blur, Shader* s_bloom)
43 	: _swapper(w, h, Bloom_sRGB), _shader_blur(s_blur), _shader_bloom(s_bloom), _width(w), _height(h) {}
44 
width()45 	GLuint width() { return _width; }
height()46 	GLuint height() { return _height; }
47 
begin()48 	void begin() {
49 		_swapper.activate();
50 		glDisable(GL_FRAMEBUFFER_SRGB_EXT); // don't blend for initial
51 	}
52 
end()53 	void end() {
54 		_swapper.swap();
55 	}
56 
draw(FBOSwapper & dest)57 	void draw(FBOSwapper& dest) {
58 
59 		int passes = _shader_bloom->passes();
60 		if (passes < 0)
61 			passes = 5;
62 
63 		glBlendFunc(GL_SRC_ALPHA,GL_ONE);
64 		for (int i = 0; i < passes; i++) {
65 			_shader_blur->enable();
66 			_shader_blur->setFloat(Shader::U_OffsetX, 1);
67 			_shader_blur->setFloat(Shader::U_OffsetY, 0);
68 			_shader_blur->setFloat(Shader::U_Pass, i + 1);
69 			_swapper.filter(false);
70 
71 			_shader_blur->setFloat(Shader::U_OffsetX, 0);
72 			_shader_blur->setFloat(Shader::U_OffsetY, 1);
73 			_shader_blur->setFloat(Shader::U_Pass, i + 1);
74 			_swapper.filter(false);
75 
76 			_shader_bloom->enable();
77 			_shader_bloom->setFloat(Shader::U_Pass, i + 1);
78 //			if (Bloom_sRGB)
79 //				dest.blend(_swapper.current_contents(), true);
80 //			else
81 				dest.blend_multisample(_swapper.current_contents());
82 
83 			Shader::disable();
84 		}
85 
86 		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
87 	}
88 };
89 
90 
91 RenderRasterize_Shader::RenderRasterize_Shader() = default;
92 RenderRasterize_Shader::~RenderRasterize_Shader() = default;
93 
94 /*
95  * initialize some stuff
96  * happens once after opengl, shaders and textures are setup
97  */
setupGL(Rasterizer_Shader_Class & Rasterizer)98 void RenderRasterize_Shader::setupGL(Rasterizer_Shader_Class& Rasterizer) {
99 
100 	RasPtr = &Rasterizer;
101 
102 	Shader::loadAll();
103 
104 	Shader* s_blur = Shader::get(Shader::S_Blur);
105 	Shader* s_bloom = Shader::get(Shader::S_Bloom);
106 
107 	blur.reset();
108 	if(TEST_FLAG(Get_OGL_ConfigureData().Flags, OGL_Flag_Blur)) {
109 		if(s_blur && s_bloom) {
110 			blur.reset(new Blur(640., 640. * graphics_preferences->screen_mode.height / graphics_preferences->screen_mode.width, s_blur, s_bloom));
111 		}
112 	}
113 
114 //	glDisable(GL_CULL_FACE);
115 //	glDisable(GL_LIGHTING);
116 }
117 
118 /*
119  * override for RenderRasterizerClass::render_tree()
120  *
121  * with multiple rendering passes for glow effect
122  */
123 const double TWO_PI = 8*atan(1.0);
124 const float FixedAngleToRadians = TWO_PI/(float(FIXED_ONE)*float(FULL_CIRCLE));
125 const float FixedAngleToDegrees = 360.0/(float(FIXED_ONE)*float(FULL_CIRCLE));
126 
render_tree()127 void RenderRasterize_Shader::render_tree() {
128 
129 	weaponFlare = PIN(view->maximum_depth_intensity - NATURAL_LIGHT_INTENSITY, 0, FIXED_ONE)/float(FIXED_ONE);
130 	selfLuminosity = PIN(NATURAL_LIGHT_INTENSITY, 0, FIXED_ONE)/float(FIXED_ONE);
131 
132 	Shader* s = Shader::get(Shader::S_Invincible);
133 	s->enable();
134 	s->setFloat(Shader::U_Time, view->tick_count);
135 	s->setFloat(Shader::U_LogicalWidth, view->screen_width);
136 	s->setFloat(Shader::U_LogicalHeight, view->screen_height);
137 	s->setFloat(Shader::U_PixelWidth, view->screen_width * MainScreenPixelScale());
138 	s->setFloat(Shader::U_PixelHeight, view->screen_height * MainScreenPixelScale());
139 	if (blur.get()) {
140 		s = Shader::get(Shader::S_InvincibleBloom);
141 		s->enable();
142 		s->setFloat(Shader::U_Time, view->tick_count);
143 		s->setFloat(Shader::U_LogicalWidth, view->screen_width);
144 		s->setFloat(Shader::U_LogicalHeight, view->screen_height);
145 		s->setFloat(Shader::U_PixelWidth, blur->width());
146 		s->setFloat(Shader::U_PixelHeight, blur->height());
147 	}
148 
149 	short leftmost = INT16_MAX;
150 	short rightmost = INT16_MIN;
151 	vector<clipping_window_data>& windows = RSPtr->RVPtr->ClippingWindows;
152 	for (vector<clipping_window_data>::const_iterator it = windows.begin(); it != windows.end(); ++it) {
153 		if (it->x0 < leftmost) {
154 			leftmost = it->x0;
155 			leftmost_clip = it->left;
156 		}
157 		if (it->x1 > rightmost) {
158 			rightmost = it->x1;
159 			rightmost_clip = it->right;
160 		}
161 	}
162 
163 	bool usefog = false;
164 	int fogtype;
165 	OGL_FogData *fogdata;
166 	if (TEST_FLAG(Get_OGL_ConfigureData().Flags,OGL_Flag_Fog))
167 	{
168 		fogtype = (current_player->variables.flags&_HEAD_BELOW_MEDIA_BIT) ?
169 		OGL_Fog_BelowLiquid : OGL_Fog_AboveLiquid;
170 		fogdata = OGL_GetFogData(fogtype);
171 		if (fogdata && fogdata->IsPresent && fogdata->AffectsLandscapes) {
172 			usefog = true;
173 		}
174 	}
175 	const float virtual_yaw = view->virtual_yaw * FixedAngleToRadians;
176 	const float virtual_pitch = view->virtual_pitch * FixedAngleToRadians;
177 	s = Shader::get(Shader::S_Landscape);
178 	s->enable();
179 	s->setFloat(Shader::U_UseFog, usefog ? 1.0 : 0.0);
180 	s->setFloat(Shader::U_Yaw, virtual_yaw);
181 	s->setFloat(Shader::U_Pitch, view->mimic_sw_perspective ? 0.0 : virtual_pitch);
182 	s = Shader::get(Shader::S_LandscapeBloom);
183 	s->enable();
184 	s->setFloat(Shader::U_UseFog, usefog ? 1.0 : 0.0);
185 	s->setFloat(Shader::U_Yaw, virtual_yaw);
186 	s->setFloat(Shader::U_Pitch, view->mimic_sw_perspective ? 0.0 : virtual_pitch);
187 	Shader::disable();
188 
189 	RenderRasterizerClass::render_tree(kDiffuse);
190         render_viewer_sprite_layer(kDiffuse);
191 
192 	if (TEST_FLAG(Get_OGL_ConfigureData().Flags, OGL_Flag_Blur) && blur.get()) {
193 		blur->begin();
194 		RenderRasterizerClass::render_tree(kGlow);
195                 render_viewer_sprite_layer(kGlow);
196 		blur->end();
197 		RasPtr->swapper->deactivate();
198 		blur->draw(*RasPtr->swapper);
199 		RasPtr->swapper->activate();
200 	}
201 
202 	glAlphaFunc(GL_GREATER, 0.5);
203 }
204 
render_node(sorted_node_data * node,bool SeeThruLiquids,RenderStep renderStep)205 void RenderRasterize_Shader::render_node(sorted_node_data *node, bool SeeThruLiquids, RenderStep renderStep)
206 {
207 	// parasitic object detection
208     objectCount = 0;
209     objectY = 0;
210 
211     RenderRasterizerClass::render_node(node, SeeThruLiquids, renderStep);
212 
213 	// turn off clipping planes
214 	glDisable(GL_CLIP_PLANE0);
215 	glDisable(GL_CLIP_PLANE1);
216 }
217 
clip_to_window(clipping_window_data * win)218 void RenderRasterize_Shader::clip_to_window(clipping_window_data *win)
219 {
220     GLdouble clip[] = { 0., 0., 0., 0. };
221 
222     // recenter to player's orientation temporarily
223     glPushMatrix();
224     glTranslatef(view->origin.x, view->origin.y, 0.);
225     glRotatef(view->yaw * (360/float(FULL_CIRCLE)) + 90., 0., 0., 1.);
226 
227     glRotatef(-0.1, 0., 0., 1.); // leave some excess to avoid artifacts at edges
228 	if (win->left.i != leftmost_clip.i || win->left.j != leftmost_clip.j) {
229 		clip[0] = win->left.i;
230 		clip[1] = win->left.j;
231 		glEnable(GL_CLIP_PLANE0);
232 		glClipPlane(GL_CLIP_PLANE0, clip);
233 	} else {
234 		glDisable(GL_CLIP_PLANE0);
235 	}
236 
237     glRotatef(0.2, 0., 0., 1.); // breathing room for right-hand clip
238 	if (win->right.i != rightmost_clip.i || win->right.j != rightmost_clip.j) {
239 		clip[0] = win->right.i;
240 		clip[1] = win->right.j;
241 		glEnable(GL_CLIP_PLANE1);
242 		glClipPlane(GL_CLIP_PLANE1, clip);
243 	} else {
244 		glDisable(GL_CLIP_PLANE1);
245 	}
246 
247     glPopMatrix();
248 }
249 
store_endpoint(endpoint_data * endpoint,long_vector2d & p)250 void RenderRasterize_Shader::store_endpoint(
251 	endpoint_data *endpoint,
252 	long_vector2d& p)
253 {
254 	p.i = endpoint->vertex.x;
255 	p.j = endpoint->vertex.y;
256 }
257 
258 
setupSpriteTexture(const rectangle_definition & rect,short type,float offset,RenderStep renderStep)259 TextureManager RenderRasterize_Shader::setupSpriteTexture(const rectangle_definition& rect, short type, float offset, RenderStep renderStep) {
260 
261 	Shader *s = NULL;
262 	GLfloat color[3];
263 	GLdouble shade = PIN(static_cast<GLfloat>(rect.ambient_shade)/static_cast<GLfloat>(FIXED_ONE),0,1);
264 	color[0] = color[1] = color[2] = shade;
265 
266 	TextureManager TMgr;
267 
268 	TMgr.ShapeDesc = rect.ShapeDesc;
269 	TMgr.LowLevelShape = rect.LowLevelShape;
270 	TMgr.ShadingTables = rect.shading_tables;
271 	TMgr.Texture = rect.texture;
272 	TMgr.TransferMode = rect.transfer_mode;
273 	TMgr.TransferData = rect.transfer_data;
274 	TMgr.IsShadeless = (rect.flags&_SHADELESS_BIT) != 0;
275 	TMgr.TextureType = type;
276 
277 	float flare = weaponFlare;
278 
279 	glEnable(GL_TEXTURE_2D);
280 	glColor4f(color[0], color[1], color[2], 1);
281 
282 	switch(TMgr.TransferMode) {
283 		case _static_transfer:
284 			TMgr.IsShadeless = 1;
285 			flare = -1;
286 			s = Shader::get(renderStep == kGlow ? Shader::S_InvincibleBloom : Shader::S_Invincible);
287 			s->enable();
288 			break;
289 		case _tinted_transfer:
290 			flare = -1;
291 			s = Shader::get(renderStep == kGlow ? Shader::S_InvisibleBloom : Shader::S_Invisible);
292 			s->enable();
293 			s->setFloat(Shader::U_Visibility, 1.0 - rect.transfer_data/32.0f);
294 			break;
295 		case _solid_transfer:
296 			glColor4f(0,1,0,1);
297 			break;
298 		case _textured_transfer:
299 			if(TMgr.IsShadeless) {
300 				if (renderStep == kDiffuse) {
301 					glColor4f(1,1,1,1);
302 				} else {
303 					glColor4f(0,0,0,1);
304 				}
305 				flare = -1;
306 			}
307 			break;
308 		default:
309 			glColor4f(0,0,1,1);
310 	}
311 
312 	if(s == NULL) {
313 		s = Shader::get(renderStep == kGlow ? Shader::S_SpriteBloom : Shader::S_Sprite);
314 		s->enable();
315 	}
316 
317 	if(TMgr.Setup()) {
318 		TMgr.RenderNormal();
319 	} else {
320 		TMgr.ShapeDesc = UNONE;
321 		return TMgr;
322 	}
323 
324 	TMgr.SetupTextureMatrix();
325 
326 	if (renderStep == kGlow) {
327 		s->setFloat(Shader::U_BloomScale, TMgr.BloomScale());
328 		s->setFloat(Shader::U_BloomShift, TMgr.BloomShift());
329 	}
330 	s->setFloat(Shader::U_Flare, flare);
331 	s->setFloat(Shader::U_SelfLuminosity, selfLuminosity);
332 	s->setFloat(Shader::U_Pulsate, 0);
333 	s->setFloat(Shader::U_Wobble, 0);
334 	s->setFloat(Shader::U_Depth, offset);
335 	s->setFloat(Shader::U_StrictDepthMode, OGL_ForceSpriteDepth() ? 1 : 0);
336 	s->setFloat(Shader::U_Glow, 0);
337 	return TMgr;
338 }
339 
340 // Circle constants
341 const double Radian2Circle = 1/TWO_PI;			// A circle is 2*pi radians
342 const double FullCircleReciprocal = 1/double(FULL_CIRCLE);
343 
setupWallTexture(const shape_descriptor & Texture,short transferMode,float pulsate,float wobble,float intensity,float offset,RenderStep renderStep)344 TextureManager RenderRasterize_Shader::setupWallTexture(const shape_descriptor& Texture, short transferMode, float pulsate, float wobble, float intensity, float offset, RenderStep renderStep) {
345 
346 	Shader *s = NULL;
347 
348 	TextureManager TMgr;
349 	LandscapeOptions *opts = NULL;
350 	TMgr.ShapeDesc = Texture;
351 	if (TMgr.ShapeDesc == UNONE) { return TMgr; }
352 	get_shape_bitmap_and_shading_table(Texture, &TMgr.Texture, &TMgr.ShadingTables,
353 		current_player->infravision_duration ? _shading_infravision : _shading_normal);
354 
355 	TMgr.TransferMode = _textured_transfer;
356 	TMgr.IsShadeless = current_player->infravision_duration ? 1 : 0;
357 	TMgr.TransferData = 0;
358 
359 	float flare = weaponFlare;
360 
361 	glEnable(GL_TEXTURE_2D);
362 	glColor4f(intensity, intensity, intensity, 1.0);
363 
364 	switch(transferMode) {
365 		case _xfer_static:
366 			TMgr.TextureType = OGL_Txtr_Wall;
367 			TMgr.TransferMode = _static_transfer;
368 			TMgr.IsShadeless = 1;
369 			flare = -1;
370 			s = Shader::get(renderStep == kGlow ? Shader::S_InvincibleBloom : Shader::S_Invincible);
371 			s->enable();
372 			break;
373 		case _xfer_landscape:
374 		case _xfer_big_landscape:
375 		{
376 			TMgr.TextureType = OGL_Txtr_Landscape;
377 			TMgr.TransferMode = _big_landscaped_transfer;
378 			opts = View_GetLandscapeOptions(Texture);
379 			TMgr.LandscapeVertRepeat = opts->VertRepeat;
380 			TMgr.Landscape_AspRatExp = opts->OGL_AspRatExp;
381 			s = Shader::get(renderStep == kGlow ? Shader::S_LandscapeBloom : Shader::S_Landscape);
382 			s->enable();
383 		}
384 			break;
385 		default:
386 			TMgr.TextureType = OGL_Txtr_Wall;
387 			if(TMgr.IsShadeless) {
388 				if (renderStep == kDiffuse) {
389 					glColor4f(1,1,1,1);
390 				} else {
391 					glColor4f(0,0,0,1);
392 				}
393 				flare = -1;
394 			}
395 	}
396 
397 	if(s == NULL) {
398 		if(TEST_FLAG(Get_OGL_ConfigureData().Flags, OGL_Flag_BumpMap)) {
399 			s = Shader::get(renderStep == kGlow ? Shader::S_BumpBloom : Shader::S_Bump);
400 		} else {
401 			s = Shader::get(renderStep == kGlow ? Shader::S_WallBloom : Shader::S_Wall);
402 		}
403 		s->enable();
404 	}
405 
406 	if(TMgr.Setup()) {
407 		TMgr.RenderNormal(); // must allocate first
408 		if (TEST_FLAG(Get_OGL_ConfigureData().Flags, OGL_Flag_BumpMap)) {
409 			glActiveTextureARB(GL_TEXTURE1_ARB);
410 			TMgr.RenderBump();
411 			glActiveTextureARB(GL_TEXTURE0_ARB);
412 		}
413 	} else {
414 		TMgr.ShapeDesc = UNONE;
415 		return TMgr;
416 	}
417 
418 	TMgr.SetupTextureMatrix();
419 
420 	if (TMgr.TextureType == OGL_Txtr_Landscape && opts) {
421 		double TexScale = ABS(TMgr.U_Scale);
422 		double HorizScale = double(1 << opts->HorizExp);
423 		s->setFloat(Shader::U_ScaleX, HorizScale * (npotTextures ? 1.0 : TexScale) * Radian2Circle);
424 		s->setFloat(Shader::U_OffsetX, HorizScale * (0.25 + opts->Azimuth * FullCircleReciprocal));
425 
426 		short AdjustedVertExp = opts->VertExp + opts->OGL_AspRatExp;
427 		double VertScale = (AdjustedVertExp >= 0) ? double(1 << AdjustedVertExp)
428 		                                          : 1/double(1 << (-AdjustedVertExp));
429 		s->setFloat(Shader::U_ScaleY, VertScale * TexScale * Radian2Circle);
430 		s->setFloat(Shader::U_OffsetY, (0.5 + TMgr.U_Offset) * TexScale);
431 	}
432 
433 	if (renderStep == kGlow) {
434 		if (TMgr.TextureType == OGL_Txtr_Landscape) {
435 			s->setFloat(Shader::U_BloomScale, TMgr.LandscapeBloom());
436 		} else {
437 			s->setFloat(Shader::U_BloomScale, TMgr.BloomScale());
438 			s->setFloat(Shader::U_BloomShift, TMgr.BloomShift());
439 		}
440 	}
441 	s->setFloat(Shader::U_Flare, flare);
442 	s->setFloat(Shader::U_SelfLuminosity, selfLuminosity);
443 	s->setFloat(Shader::U_Pulsate, pulsate);
444 	s->setFloat(Shader::U_Wobble, wobble);
445 	s->setFloat(Shader::U_Depth, offset);
446 	s->setFloat(Shader::U_Glow, 0);
447 	return TMgr;
448 }
449 
instantiate_transfer_mode(struct view_data * view,short transfer_mode,world_distance & x0,world_distance & y0)450 void instantiate_transfer_mode(struct view_data *view, short transfer_mode, world_distance &x0, world_distance &y0) {
451 	short alternate_transfer_phase;
452 	short transfer_phase = view->tick_count;
453 
454 	switch (transfer_mode) {
455 
456 		case _xfer_fast_horizontal_slide:
457 		case _xfer_horizontal_slide:
458 		case _xfer_vertical_slide:
459 		case _xfer_fast_vertical_slide:
460 		case _xfer_wander:
461 		case _xfer_fast_wander:
462 			x0 = y0= 0;
463 			switch (transfer_mode) {
464 				case _xfer_fast_horizontal_slide: transfer_phase<<= 1;
465 				case _xfer_horizontal_slide: x0= (transfer_phase<<2)&(WORLD_ONE-1); break;
466 
467 				case _xfer_fast_vertical_slide: transfer_phase<<= 1;
468 				case _xfer_vertical_slide: y0= (transfer_phase<<2)&(WORLD_ONE-1); break;
469 
470 				case _xfer_fast_wander: transfer_phase<<= 1;
471 				case _xfer_wander:
472 					alternate_transfer_phase= transfer_phase%(10*FULL_CIRCLE);
473 					transfer_phase= transfer_phase%(6*FULL_CIRCLE);
474 					x0 = (cosine_table[NORMALIZE_ANGLE(alternate_transfer_phase)] +
475 						 (cosine_table[NORMALIZE_ANGLE(2*alternate_transfer_phase)]>>1) +
476 						 (cosine_table[NORMALIZE_ANGLE(5*alternate_transfer_phase)]>>1))>>(WORLD_FRACTIONAL_BITS-TRIG_SHIFT+2);
477 					y0 = (sine_table[NORMALIZE_ANGLE(transfer_phase)] +
478 						 (sine_table[NORMALIZE_ANGLE(2*transfer_phase)]>>1) +
479 						 (sine_table[NORMALIZE_ANGLE(3*transfer_phase)]>>1))>>(WORLD_FRACTIONAL_BITS-TRIG_SHIFT+2);
480 					break;
481 			}
482 			break;
483 		// wobble is done in the shader
484 		default:
485 			break;
486 	}
487 }
488 
calcWobble(short transferMode,short transfer_phase)489 float calcWobble(short transferMode, short transfer_phase) {
490 	float wobble = 0;
491 	switch(transferMode) {
492 		case _xfer_fast_wobble:
493 			transfer_phase*= 15;
494 		case _xfer_pulsate:
495 		case _xfer_wobble:
496 			transfer_phase&= WORLD_ONE/16-1;
497 			transfer_phase= (transfer_phase>=WORLD_ONE/32) ? (WORLD_ONE/32+WORLD_ONE/64 - transfer_phase) : (transfer_phase - WORLD_ONE/64);
498 			wobble = transfer_phase / 1024.0;
499 			break;
500 	}
501 	return wobble;
502 }
503 
setupBlendFunc(short blendType)504 void setupBlendFunc(short blendType) {
505 	switch(blendType)
506 	{
507 		case OGL_BlendType_Crossfade:
508 			glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
509 			break;
510 		case OGL_BlendType_Add:
511 			glBlendFunc(GL_SRC_ALPHA,GL_ONE);
512 			break;
513 		case OGL_BlendType_Crossfade_Premult:
514 			glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
515 			break;
516 		case OGL_BlendType_Add_Premult:
517 			glBlendFunc(GL_ONE, GL_ONE);
518 			break;
519 	}
520 }
521 
setupGlow(struct view_data * view,TextureManager & TMgr,float wobble,float intensity,float flare,float selfLuminosity,float offset,RenderStep renderStep)522 bool setupGlow(struct view_data *view, TextureManager &TMgr, float wobble, float intensity, float flare, float selfLuminosity, float offset, RenderStep renderStep) {
523 	if (TMgr.TransferMode == _textured_transfer && TMgr.IsGlowMapped()) {
524 		Shader *s = NULL;
525 		if (TMgr.TextureType == OGL_Txtr_Wall) {
526 			if (TEST_FLAG(Get_OGL_ConfigureData().Flags, OGL_Flag_BumpMap)) {
527 				s = Shader::get(renderStep == kGlow ? Shader::S_BumpBloom : Shader::S_Bump);
528 			} else {
529 				s = Shader::get(renderStep == kGlow ? Shader::S_WallBloom : Shader::S_Wall);
530 			}
531 		} else {
532 			s = Shader::get(renderStep == kGlow ? Shader::S_SpriteBloom : Shader::S_Sprite);
533 		}
534 
535 		TMgr.RenderGlowing();
536 		setupBlendFunc(TMgr.GlowBlend());
537 		glEnable(GL_TEXTURE_2D);
538 		glEnable(GL_BLEND);
539 		glEnable(GL_ALPHA_TEST);
540 		glAlphaFunc(GL_GREATER, 0.001);
541 
542 		s->enable();
543 		if (renderStep == kGlow) {
544 			s->setFloat(Shader::U_BloomScale, TMgr.GlowBloomScale());
545 			s->setFloat(Shader::U_BloomShift, TMgr.GlowBloomShift());
546 		}
547 		s->setFloat(Shader::U_Flare, flare);
548 		s->setFloat(Shader::U_SelfLuminosity, selfLuminosity);
549 		s->setFloat(Shader::U_Wobble, wobble);
550 		s->setFloat(Shader::U_Depth, offset - 1.0);
551 		s->setFloat(Shader::U_Glow, TMgr.MinGlowIntensity());
552 		return true;
553 	}
554 	return false;
555 }
556 
render_node_floor_or_ceiling(clipping_window_data * window,polygon_data * polygon,horizontal_surface_data * surface,bool void_present,bool ceil,RenderStep renderStep)557 void RenderRasterize_Shader::render_node_floor_or_ceiling(clipping_window_data *window,
558 	polygon_data *polygon, horizontal_surface_data *surface, bool void_present, bool ceil, RenderStep renderStep) {
559 
560 	float offset = 0;
561 
562 	const shape_descriptor& texture = AnimTxtr_Translate(surface->texture);
563 	float intensity = get_light_intensity(surface->lightsource_index) / float(FIXED_ONE - 1);
564 	float wobble = calcWobble(surface->transfer_mode, view->tick_count);
565 	// note: wobble and pulsate behave the same way on floors and ceilings
566 	// note 2: stronger wobble looks more like classic with default shaders
567 	TextureManager TMgr = setupWallTexture(texture, surface->transfer_mode, wobble * 4.0, 0, intensity, offset, renderStep);
568 	if(TMgr.ShapeDesc == UNONE) { return; }
569 
570 	if (TMgr.IsBlended()) {
571 		glEnable(GL_BLEND);
572 		setupBlendFunc(TMgr.NormalBlend());
573 		glEnable(GL_ALPHA_TEST);
574 		glAlphaFunc(GL_GREATER, 0.001);
575 	} else {
576 		glDisable(GL_BLEND);
577 		glEnable(GL_ALPHA_TEST);
578 		glAlphaFunc(GL_GREATER, 0.5);
579 	}
580 
581 //	if (void_present) {
582 //		glDisable(GL_BLEND);
583 //		glDisable(GL_ALPHA_TEST);
584 //	}
585 
586 	short vertex_count = polygon->vertex_count;
587 
588 	if (vertex_count) {
589         clip_to_window(window);
590 
591 		world_distance x = 0.0, y = 0.0;
592 		instantiate_transfer_mode(view, surface->transfer_mode, x, y);
593 
594 		vec3 N;
595 		vec3 T;
596 		float sign;
597 		if(ceil) {
598 			N = vec3(0,0,-1);
599 			T = vec3(0,1,0);
600 			sign = 1;
601 		} else {
602 			N = vec3(0,0,1);
603 			T = vec3(0,1,0);
604 			sign = -1;
605 		}
606 		glNormal3f(N[0], N[1], N[2]);
607 		glMultiTexCoord4fARB(GL_TEXTURE1_ARB, T[0], T[1], T[2], sign);
608 
609 		GLfloat vertex_array[MAXIMUM_VERTICES_PER_POLYGON * 3];
610 		GLfloat texcoord_array[MAXIMUM_VERTICES_PER_POLYGON * 2];
611 
612 		GLfloat* vp = vertex_array;
613 		GLfloat* tp = texcoord_array;
614 		if (ceil)
615 		{
616 			for(short i = 0; i < vertex_count; ++i) {
617 				world_point2d vertex = get_endpoint_data(polygon->endpoint_indexes[vertex_count - 1 - i])->vertex;
618 				*vp++ = vertex.x;
619 				*vp++ = vertex.y;
620 				*vp++ = surface->height;
621 				*tp++ = (vertex.x + surface->origin.x + x) / float(WORLD_ONE);
622 				*tp++ = (vertex.y + surface->origin.y + y) / float(WORLD_ONE);
623 			}
624 		}
625 		else
626 		{
627 			for(short i=0; i<vertex_count; ++i) {
628 				world_point2d vertex = get_endpoint_data(polygon->endpoint_indexes[i])->vertex;
629 				*vp++ = vertex.x;
630 				*vp++ = vertex.y;
631 				*vp++ = surface->height;
632 				*tp++ = (vertex.x + surface->origin.x + x) / float(WORLD_ONE);
633 				*tp++ = (vertex.y + surface->origin.y + y) / float(WORLD_ONE);
634 			}
635 		}
636 		glVertexPointer(3, GL_FLOAT, 0, vertex_array);
637 		glTexCoordPointer(2, GL_FLOAT, 0, texcoord_array);
638 
639 		glDrawArrays(GL_POLYGON, 0, vertex_count);
640 
641 		if (setupGlow(view, TMgr, wobble, intensity, weaponFlare, selfLuminosity, offset, renderStep)) {
642 			glDrawArrays(GL_POLYGON, 0, vertex_count);
643 		}
644 
645 		Shader::disable();
646 		glMatrixMode(GL_TEXTURE);
647 		glLoadIdentity();
648 		glMatrixMode(GL_MODELVIEW);
649 	}
650 }
651 
render_node_side(clipping_window_data * window,vertical_surface_data * surface,bool void_present,RenderStep renderStep)652 void RenderRasterize_Shader::render_node_side(clipping_window_data *window, vertical_surface_data *surface, bool void_present, RenderStep renderStep) {
653 
654 	float offset = 0;
655 	if (!void_present) {
656 		offset = -2.0;
657 	}
658 
659 	const shape_descriptor& texture = AnimTxtr_Translate(surface->texture_definition->texture);
660 	float intensity = (get_light_intensity(surface->lightsource_index) + surface->ambient_delta) / float(FIXED_ONE - 1);
661 	float wobble = calcWobble(surface->transfer_mode, view->tick_count);
662 	float pulsate = 0;
663 	if (surface->transfer_mode == _xfer_pulsate) {
664 		pulsate = wobble;
665 		wobble = 0;
666 	}
667 	TextureManager TMgr = setupWallTexture(texture, surface->transfer_mode, pulsate, wobble, intensity, offset, renderStep);
668 	if(TMgr.ShapeDesc == UNONE) { return; }
669 
670 	if (TMgr.IsBlended()) {
671 		glEnable(GL_BLEND);
672 		setupBlendFunc(TMgr.NormalBlend());
673 		glEnable(GL_ALPHA_TEST);
674 		glAlphaFunc(GL_GREATER, 0.001);
675 	} else {
676 		glDisable(GL_BLEND);
677 		glEnable(GL_ALPHA_TEST);
678 		glAlphaFunc(GL_GREATER, 0.5);
679 	}
680 
681 //	if (void_present) {
682 //		glDisable(GL_BLEND);
683 //		glDisable(GL_ALPHA_TEST);
684 //	}
685 
686 	world_distance h= MIN(surface->h1, surface->hmax);
687 
688 	if (h>surface->h0) {
689 
690 		world_point2d vertex[2];
691 		uint16 flags;
692 		flagged_world_point3d vertices[MAXIMUM_VERTICES_PER_WORLD_POLYGON];
693 		short vertex_count;
694 
695 		/* initialize the two posts of our trapezoid */
696 		vertex_count= 2;
697 		long_to_overflow_short_2d(surface->p0, vertex[0], flags);
698 		long_to_overflow_short_2d(surface->p1, vertex[1], flags);
699 
700 		if (vertex_count) {
701             clip_to_window(window);
702 
703 			vertex_count= 4;
704 			vertices[0].z= vertices[1].z= h + view->origin.z;
705 			vertices[2].z= vertices[3].z= surface->h0 + view->origin.z;
706 			vertices[0].x= vertices[3].x= vertex[0].x, vertices[0].y= vertices[3].y= vertex[0].y;
707 			vertices[1].x= vertices[2].x= vertex[1].x, vertices[1].y= vertices[2].y= vertex[1].y;
708 			vertices[0].flags = vertices[3].flags = 0;
709 			vertices[1].flags = vertices[2].flags = 0;
710 
711 			double div = WORLD_ONE;
712 			double dx = (surface->p1.i - surface->p0.i) / double(surface->length);
713 			double dy = (surface->p1.j - surface->p0.j) / double(surface->length);
714 
715 			world_distance x0 = WORLD_FRACTIONAL_PART(surface->texture_definition->x0);
716 			world_distance y0 = WORLD_FRACTIONAL_PART(surface->texture_definition->y0);
717 
718 			double tOffset = surface->h1 + view->origin.z + y0;
719 
720 			vec3 N(-dy, dx, 0);
721 			vec3 T(dx, dy, 0);
722 			float sign = 1;
723 			glNormal3f(N[0], N[1], N[2]);
724 			glMultiTexCoord4fARB(GL_TEXTURE1_ARB, T[0], T[1], T[2], sign);
725 
726 			world_distance x = 0.0, y = 0.0;
727 			instantiate_transfer_mode(view, surface->transfer_mode, x, y);
728 
729 			x0 -= x;
730 			tOffset -= y;
731 
732 			GLfloat vertex_array[12];
733 			GLfloat texcoord_array[8];
734 
735 			GLfloat* vp = vertex_array;
736 			GLfloat* tp = texcoord_array;
737 
738 			for(int i = 0; i < vertex_count; ++i) {
739 				float p2 = 0;
740 				if(i == 1 || i == 2) { p2 = surface->length; }
741 
742 				*vp++ = vertices[i].x;
743 				*vp++ = vertices[i].y;
744 				*vp++ = vertices[i].z;
745 				*tp++ = (tOffset - vertices[i].z) / div;
746 				*tp++ = (x0+p2) / div;
747 			}
748 			glVertexPointer(3, GL_FLOAT, 0, vertex_array);
749 			glTexCoordPointer(2, GL_FLOAT, 0, texcoord_array);
750 
751 			glDrawArrays(GL_QUADS, 0, vertex_count);
752 
753 			if (setupGlow(view, TMgr, wobble, intensity, weaponFlare, selfLuminosity, offset, renderStep)) {
754 				glDrawArrays(GL_QUADS, 0, vertex_count);
755 			}
756 
757 			Shader::disable();
758 			glMatrixMode(GL_TEXTURE);
759 			glLoadIdentity();
760 			glMatrixMode(GL_MODELVIEW);
761 		}
762 	}
763 }
764 
765 extern void FlatBumpTexture(); // from OGL_Textures.cpp
766 
RenderModel(rectangle_definition & RenderRectangle,short Collection,short CLUT,float flare,float selfLuminosity,RenderStep renderStep)767 bool RenderModel(rectangle_definition& RenderRectangle, short Collection, short CLUT, float flare, float selfLuminosity, RenderStep renderStep) {
768 
769 	OGL_ModelData *ModelPtr = RenderRectangle.ModelPtr;
770 	OGL_SkinData *SkinPtr = ModelPtr->GetSkin(CLUT);
771 	if(!SkinPtr) { return false; }
772 
773 	if (ModelPtr->Sidedness < 0) {
774 		glEnable(GL_CULL_FACE);
775 		glFrontFace(GL_CCW);
776 	} else if (ModelPtr->Sidedness > 0) {
777 		glEnable(GL_CULL_FACE);
778 		glFrontFace(GL_CW);
779 	} else {
780 		glDisable(GL_CULL_FACE);
781 	}
782 
783 	glEnable(GL_TEXTURE_2D);
784 	if (SkinPtr->OpacityType != OGL_OpacType_Crisp || RenderRectangle.transfer_mode == _tinted_transfer) {
785 		glEnable(GL_BLEND);
786 		setupBlendFunc(SkinPtr->NormalBlend);
787 		glEnable(GL_ALPHA_TEST);
788 		glAlphaFunc(GL_GREATER, 0.001);
789 	} else {
790 		glDisable(GL_BLEND);
791 		glEnable(GL_ALPHA_TEST);
792 		glAlphaFunc(GL_GREATER, 0.5);
793 	}
794 
795 	GLfloat color[3];
796 	GLdouble shade = PIN(static_cast<GLfloat>(RenderRectangle.ambient_shade)/static_cast<GLfloat>(FIXED_ONE),0,1);
797 	color[0] = color[1] = color[2] = shade;
798 	glColor4f(color[0], color[1], color[2], 1.0);
799 
800 	Shader *s = NULL;
801 	bool canGlow = false;
802 	switch(RenderRectangle.transfer_mode) {
803 		case _static_transfer:
804 			flare = -1;
805 			s = Shader::get(renderStep == kGlow ? Shader::S_InvincibleBloom : Shader::S_Invincible);
806 			s->enable();
807 			break;
808 		case _tinted_transfer:
809 			flare = -1;
810 			s = Shader::get(renderStep == kGlow ? Shader::S_InvisibleBloom : Shader::S_Invisible);
811 			s->enable();
812 			s->setFloat(Shader::U_Visibility, 1.0 - RenderRectangle.transfer_data/32.0f);
813 			break;
814 		case _solid_transfer:
815 			glColor4f(0,1,0,1);
816 			break;
817 		case _textured_transfer:
818 			if((RenderRectangle.flags&_SHADELESS_BIT) != 0) {
819 				if (renderStep == kDiffuse) {
820 					glColor4f(1,1,1,1);
821 				} else {
822 					glColor4f(0,0,0,1);
823 				}
824 				flare = -1;
825 			} else {
826 				canGlow = true;
827 			}
828 			break;
829 		default:
830 			glColor4f(0,0,1,1);
831 	}
832 
833 	if(s == NULL) {
834 		if(TEST_FLAG(Get_OGL_ConfigureData().Flags, OGL_Flag_BumpMap)) {
835 			s = Shader::get(renderStep == kGlow ? Shader::S_BumpBloom : Shader::S_Bump);
836 		} else {
837 			s = Shader::get(renderStep == kGlow ? Shader::S_WallBloom : Shader::S_Wall);
838 		}
839 		s->enable();
840 	}
841 
842 	if (renderStep == kGlow) {
843 		s->setFloat(Shader::U_BloomScale, SkinPtr->BloomScale);
844 		s->setFloat(Shader::U_BloomShift, SkinPtr->BloomShift);
845 	}
846 	s->setFloat(Shader::U_Flare, flare);
847 	s->setFloat(Shader::U_SelfLuminosity, selfLuminosity);
848 	s->setFloat(Shader::U_Wobble, 0);
849 	s->setFloat(Shader::U_Depth, 0);
850 	s->setFloat(Shader::U_Glow, 0);
851 
852 	glVertexPointer(3,GL_FLOAT,0,ModelPtr->Model.PosBase());
853 	glClientActiveTextureARB(GL_TEXTURE0_ARB);
854 	if (ModelPtr->Model.TxtrCoords.empty()) {
855 		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
856 	} else {
857 		glTexCoordPointer(2,GL_FLOAT,0,ModelPtr->Model.TCBase());
858 	}
859 
860 	glEnableClientState(GL_NORMAL_ARRAY);
861 	glNormalPointer(GL_FLOAT,0,ModelPtr->Model.NormBase());
862 
863 	glClientActiveTextureARB(GL_TEXTURE1_ARB);
864 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
865 	glTexCoordPointer(4,GL_FLOAT,sizeof(vec4),ModelPtr->Model.TangentBase());
866 
867 	if(ModelPtr->Use(CLUT,OGL_SkinManager::Normal)) {
868 		LoadModelSkin(SkinPtr->NormalImg, Collection, CLUT);
869 	}
870 
871 	if(TEST_FLAG(Get_OGL_ConfigureData().Flags, OGL_Flag_BumpMap)) {
872 		glActiveTextureARB(GL_TEXTURE1_ARB);
873 		if(ModelPtr->Use(CLUT,OGL_SkinManager::Bump)) {
874 			LoadModelSkin(SkinPtr->OffsetImg, Collection, CLUT);
875 		}
876 		if (!SkinPtr->OffsetImg.IsPresent()) {
877 			FlatBumpTexture();
878 		}
879 		glActiveTextureARB(GL_TEXTURE0_ARB);
880 	}
881 
882 	glDrawElements(GL_TRIANGLES,(GLsizei)ModelPtr->Model.NumVI(),GL_UNSIGNED_SHORT,ModelPtr->Model.VIBase());
883 
884 	if (canGlow && SkinPtr->GlowImg.IsPresent()) {
885 		glEnable(GL_BLEND);
886 		setupBlendFunc(SkinPtr->GlowBlend);
887 		glEnable(GL_ALPHA_TEST);
888 		glAlphaFunc(GL_GREATER, 0.001);
889 
890 		s->enable();
891 		s->setFloat(Shader::U_Glow, SkinPtr->MinGlowIntensity);
892 		if (renderStep == kGlow) {
893 			s->setFloat(Shader::U_BloomScale, SkinPtr->GlowBloomScale);
894 			s->setFloat(Shader::U_BloomShift, SkinPtr->GlowBloomShift);
895 		}
896 
897 		if(ModelPtr->Use(CLUT,OGL_SkinManager::Glowing)) {
898 			LoadModelSkin(SkinPtr->GlowImg, Collection, CLUT);
899 		}
900 		glDrawElements(GL_TRIANGLES,(GLsizei)ModelPtr->Model.NumVI(),GL_UNSIGNED_SHORT,ModelPtr->Model.VIBase());
901 	}
902 
903 	glDisableClientState(GL_NORMAL_ARRAY);
904 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
905 	glClientActiveTextureARB(GL_TEXTURE0_ARB);
906 	if (ModelPtr->Model.TxtrCoords.empty()) {
907 		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
908 	}
909 
910 	// Restore the default render sidedness
911 	glEnable(GL_CULL_FACE);
912 	glFrontFace(GL_CW);
913 	Shader::disable();
914 	return true;
915 }
916 
render_node_object(render_object_data * object,bool other_side_of_media,RenderStep renderStep)917 void RenderRasterize_Shader::render_node_object(render_object_data *object, bool other_side_of_media, RenderStep renderStep) {
918 
919     if (!object->clipping_windows)
920         return;
921 
922 	clipping_window_data *win;
923 
924 	// To properly handle sprites in media, we render above and below
925 	// the media boundary in separate passes, just like the original
926 	// software renderer.
927 	short media_index = get_polygon_data(object->node->polygon_index)->media_index;
928 	media_data *media = (media_index != NONE) ? get_media_data(media_index) : NULL;
929 	if (media) {
930 		float h = media->height;
931 		GLdouble plane[] = { 0.0, 0.0, 1.0, -h };
932 		if (view->under_media_boundary ^ other_side_of_media) {
933 			plane[2] = -1.0;
934 			plane[3] = h;
935 		}
936 		glClipPlane(GL_CLIP_PLANE5, plane);
937 		glEnable(GL_CLIP_PLANE5);
938 	} else if (other_side_of_media) {
939 		// When there's no media present, we can skip the second pass.
940 		return;
941 	}
942 
943     for (win = object->clipping_windows; win; win = win->next_window)
944     {
945         clip_to_window(win);
946         _render_node_object_helper(object, renderStep);
947     }
948 
949     glDisable(GL_CLIP_PLANE5);
950 }
951 
_render_node_object_helper(render_object_data * object,RenderStep renderStep)952 void RenderRasterize_Shader::_render_node_object_helper(render_object_data *object, RenderStep renderStep) {
953 
954 	rectangle_definition& rect = object->rectangle;
955 	const world_point3d& pos = rect.Position;
956 
957 	if(rect.ModelPtr) {
958 		glPushMatrix();
959 		glTranslated(pos.x, pos.y, pos.z);
960 		glRotated((360.0/FULL_CIRCLE)*rect.Azimuth,0,0,1);
961 		GLfloat HorizScale = rect.Scale*rect.HorizScale;
962 		glScalef(HorizScale,HorizScale,rect.Scale);
963 
964 		short descriptor = GET_DESCRIPTOR_COLLECTION(rect.ShapeDesc);
965 		short collection = GET_COLLECTION(descriptor);
966 		short clut = ModifyCLUT(rect.transfer_mode,GET_COLLECTION_CLUT(descriptor));
967 
968 		RenderModel(rect, collection, clut, weaponFlare, selfLuminosity, renderStep);
969 		glPopMatrix();
970 		return;
971 	}
972 
973 	glPushMatrix();
974 	glTranslated(pos.x, pos.y, pos.z);
975 
976 	double yaw = view->virtual_yaw * FixedAngleToDegrees;
977 	glRotated(yaw, 0.0, 0.0, 1.0);
978 
979 	float offset = 0;
980 	if (OGL_ForceSpriteDepth()) {
981 		// look for parasitic objects based on y position,
982 		// and offset them to draw in proper depth order
983 		if(pos.y == objectY) {
984 			objectCount++;
985 			offset = objectCount * -1.0;
986 		} else {
987 			objectCount = 0;
988 			objectY = pos.y;
989 		}
990 	} else {
991 		glDisable(GL_DEPTH_TEST);
992 	}
993 
994 	TextureManager TMgr = setupSpriteTexture(rect, OGL_Txtr_Inhabitant, offset, renderStep);
995 	if (TMgr.ShapeDesc == UNONE) { glPopMatrix(); return; }
996 
997 	float texCoords[2][2];
998 
999 	if(rect.flip_vertical) {
1000 		texCoords[0][1] = TMgr.U_Offset;
1001 		texCoords[0][0] = TMgr.U_Scale+TMgr.U_Offset;
1002 	} else {
1003 		texCoords[0][0] = TMgr.U_Offset;
1004 		texCoords[0][1] = TMgr.U_Scale+TMgr.U_Offset;
1005 	}
1006 
1007 	if(rect.flip_horizontal) {
1008 		texCoords[1][1] = TMgr.V_Offset;
1009 		texCoords[1][0] = TMgr.V_Scale+TMgr.V_Offset;
1010 	} else {
1011 		texCoords[1][0] = TMgr.V_Offset;
1012 		texCoords[1][1] = TMgr.V_Scale+TMgr.V_Offset;
1013 	}
1014 
1015 	if(TMgr.IsBlended() || TMgr.TransferMode == _tinted_transfer) {
1016 		glEnable(GL_BLEND);
1017 		setupBlendFunc(TMgr.NormalBlend());
1018 		glEnable(GL_ALPHA_TEST);
1019 		glAlphaFunc(GL_GREATER, 0.001);
1020 	} else {
1021 		glDisable(GL_BLEND);
1022 		glEnable(GL_ALPHA_TEST);
1023 		glAlphaFunc(GL_GREATER, 0.5);
1024 	}
1025 
1026 	GLfloat vertex_array[12] = {
1027 		0,
1028 		rect.WorldLeft * rect.HorizScale * rect.Scale,
1029 		rect.WorldTop * rect.Scale,
1030 		0,
1031 		rect.WorldRight * rect.HorizScale * rect.Scale,
1032 		rect.WorldTop * rect.Scale,
1033 		0,
1034 		rect.WorldRight * rect.HorizScale * rect.Scale,
1035 		rect.WorldBottom * rect.Scale,
1036 		0,
1037 		rect.WorldLeft * rect.HorizScale * rect.Scale,
1038 		rect.WorldBottom * rect.Scale
1039 	};
1040 
1041 	GLfloat texcoord_array[8] = {
1042 		texCoords[0][0],
1043 		texCoords[1][0],
1044 		texCoords[0][0],
1045 		texCoords[1][1],
1046 		texCoords[0][1],
1047 		texCoords[1][1],
1048 		texCoords[0][1],
1049 		texCoords[1][0]
1050 	};
1051 
1052 	glVertexPointer(3, GL_FLOAT, 0, vertex_array);
1053 	glTexCoordPointer(2, GL_FLOAT, 0, texcoord_array);
1054 
1055 	glDrawArrays(GL_QUADS, 0, 4);
1056 
1057 	if (setupGlow(view, TMgr, 0, 1, weaponFlare, selfLuminosity, offset, renderStep)) {
1058 		glDrawArrays(GL_QUADS, 0, 4);
1059 	}
1060 
1061 	glEnable(GL_DEPTH_TEST);
1062 	glPopMatrix();
1063 	Shader::disable();
1064 	TMgr.RestoreTextureMatrix();
1065 }
1066 
1067 extern void position_sprite_axis(short *x0, short *x1, short scale_width, short screen_width, short positioning_mode, _fixed position, bool flip, world_distance world_left, world_distance world_right);
1068 
1069 extern GLdouble Screen_2_Clip[16];
1070 
render_viewer_sprite_layer(RenderStep renderStep)1071 void RenderRasterize_Shader::render_viewer_sprite_layer(RenderStep renderStep)
1072 {
1073         if (!view->show_weapons_in_hand) return;
1074 
1075         glMatrixMode(GL_TEXTURE);
1076         glPushMatrix();
1077 
1078         glMatrixMode(GL_PROJECTION);
1079         glPushMatrix();
1080         glLoadMatrixd(Screen_2_Clip);
1081 
1082         glMatrixMode(GL_MODELVIEW);
1083         glPushMatrix();
1084         glLoadIdentity();
1085 
1086         rectangle_definition rect;
1087 	weapon_display_information display_data;
1088 	shape_information_data *shape_information;
1089 	short count;
1090 
1091         rect.ModelPtr = nullptr;
1092         rect.Opacity = 1;
1093 
1094         /* get_weapon_display_information() returns true if there is a weapon to be drawn.  it
1095            should initially be passed a count of zero.  it returns the weaponÕs texture and
1096            enough information to draw it correctly. */
1097 	count= 0;
1098 	while (get_weapon_display_information(&count, &display_data))
1099 	{
1100 		/* fetch relevant shape data */
1101                 shape_information= extended_get_shape_information(display_data.collection, display_data.low_level_shape_index);
1102 
1103                 // Nonexistent frame: skip
1104 		if (!shape_information) continue;
1105 
1106 		// LP change: for the convenience of the OpenGL renderer
1107 		rect.ShapeDesc = BUILD_DESCRIPTOR(display_data.collection,0);
1108 		rect.LowLevelShape = display_data.low_level_shape_index;
1109 
1110 		if (shape_information->flags&_X_MIRRORED_BIT) display_data.flip_horizontal= !display_data.flip_horizontal;
1111 		if (shape_information->flags&_Y_MIRRORED_BIT) display_data.flip_vertical= !display_data.flip_vertical;
1112 
1113 		/* calculate shape rectangle */
1114 		position_sprite_axis(&rect.x0, &rect.x1, view->screen_height, view->screen_width, display_data.horizontal_positioning_mode,
1115 			display_data.horizontal_position, display_data.flip_horizontal, shape_information->world_left, shape_information->world_right);
1116 		position_sprite_axis(&rect.y0, &rect.y1, view->screen_height, view->screen_height, display_data.vertical_positioning_mode,
1117 			display_data.vertical_position, display_data.flip_vertical, -shape_information->world_top, -shape_information->world_bottom);
1118 
1119 		/* set rectangle bitmap and shading table */
1120 		extended_get_shape_bitmap_and_shading_table(display_data.collection, display_data.low_level_shape_index, &rect.texture, &rect.shading_tables, view->shading_mode);
1121 		if (!rect.texture) continue;
1122 
1123 		rect.flags= 0;
1124 
1125 		/* initialize clipping window to full screen */
1126 		rect.clip_left= 0;
1127 		rect.clip_right= view->screen_width;
1128 		rect.clip_top= 0;
1129 		rect.clip_bottom= view->screen_height;
1130 
1131 		/* copy mirror flags */
1132 		rect.flip_horizontal= display_data.flip_horizontal;
1133 		rect.flip_vertical= display_data.flip_vertical;
1134 
1135 		/* lighting: depth of zero in the cameraÕs polygon index */
1136 		rect.depth= 0;
1137 		rect.ambient_shade= get_light_intensity(get_polygon_data(view->origin_polygon_index)->floor_lightsource_index);
1138 		rect.ambient_shade= MAX(shape_information->minimum_light_intensity, rect.ambient_shade);
1139 		if (view->shading_mode==_shading_infravision) rect.flags|= _SHADELESS_BIT;
1140 
1141 		// Calculate the object's horizontal position
1142 		// for the convenience of doing teleport-in/teleport-out
1143 		rect.xc = (rect.x0 + rect.x1) >> 1;
1144 
1145                 /* make the weapon reflect the ownerÕs transfer mode */
1146 		instantiate_rectangle_transfer_mode(view, &rect, display_data.transfer_mode, display_data.transfer_phase);
1147 
1148                 render_viewer_sprite(rect, renderStep);
1149         }
1150 
1151         Shader::disable();
1152 
1153         glPopMatrix();
1154 
1155         glMatrixMode(GL_PROJECTION);
1156         glPopMatrix();
1157 
1158         glMatrixMode(GL_TEXTURE);
1159         glPopMatrix();
1160 
1161         glMatrixMode(GL_MODELVIEW);
1162 }
1163 
1164 struct ExtendedVertexData
1165 {
1166 	GLdouble Vertex[4];
1167 	GLdouble TexCoord[2];
1168 	GLfloat Color[3];
1169 	GLfloat GlowColor[3];
1170 };
1171 
render_viewer_sprite(rectangle_definition & RenderRectangle,RenderStep renderStep)1172 void RenderRasterize_Shader::render_viewer_sprite(rectangle_definition& RenderRectangle, RenderStep renderStep)
1173 {
1174 	// Find texture coordinates
1175 	ExtendedVertexData ExtendedVertexList[4];
1176 
1177 	point2d TopLeft, BottomRight;
1178 	// Clipped corners:
1179 	TopLeft.x = MAX(RenderRectangle.x0,RenderRectangle.clip_left);
1180 	TopLeft.y = MAX(RenderRectangle.y0,RenderRectangle.clip_top);
1181 	BottomRight.x = MIN(RenderRectangle.x1,RenderRectangle.clip_right);
1182 	BottomRight.y = MIN(RenderRectangle.y1,RenderRectangle.clip_bottom);
1183 
1184         // Screen coordinates; weapons-in-hand are in the foreground
1185         ExtendedVertexList[0].Vertex[0] = TopLeft.x;
1186         ExtendedVertexList[0].Vertex[1] = TopLeft.y;
1187         ExtendedVertexList[0].Vertex[2] = 1;
1188         ExtendedVertexList[2].Vertex[0] = BottomRight.x;
1189         ExtendedVertexList[2].Vertex[1] = BottomRight.y;
1190         ExtendedVertexList[2].Vertex[2] = 1;
1191 
1192 	// Completely clipped away?
1193 	if (BottomRight.x <= TopLeft.x) return;
1194 	if (BottomRight.y <= TopLeft.y) return;
1195 
1196 	// Use that texture
1197 	auto TMgr = setupSpriteTexture(RenderRectangle, OGL_Txtr_WeaponsInHand, 0, renderStep);
1198 
1199 	// Calculate the texture coordinates;
1200 	// the scanline direction is downward, (texture coordinate 0)
1201 	// while the line-to-line direction is rightward (texture coordinate 1)
1202 	GLdouble U_Scale = TMgr.U_Scale/(RenderRectangle.y1 - RenderRectangle.y0);
1203 	GLdouble V_Scale = TMgr.V_Scale/(RenderRectangle.x1 - RenderRectangle.x0);
1204 	GLdouble U_Offset = TMgr.U_Offset;
1205 	GLdouble V_Offset = TMgr.V_Offset;
1206 
1207 	if (RenderRectangle.flip_vertical)
1208 	{
1209 		ExtendedVertexList[0].TexCoord[0] = U_Offset + U_Scale*(RenderRectangle.y1 - TopLeft.y);
1210 		ExtendedVertexList[2].TexCoord[0] = U_Offset + U_Scale*(RenderRectangle.y1 - BottomRight.y);
1211 	} else {
1212 		ExtendedVertexList[0].TexCoord[0] = U_Offset + U_Scale*(TopLeft.y - RenderRectangle.y0);
1213 		ExtendedVertexList[2].TexCoord[0] = U_Offset + U_Scale*(BottomRight.y - RenderRectangle.y0);
1214 	}
1215 	if (RenderRectangle.flip_horizontal)
1216 	{
1217 		ExtendedVertexList[0].TexCoord[1] = V_Offset + V_Scale*(RenderRectangle.x1 - TopLeft.x);
1218 		ExtendedVertexList[2].TexCoord[1] = V_Offset + V_Scale*(RenderRectangle.x1 - BottomRight.x);
1219 	} else {
1220 		ExtendedVertexList[0].TexCoord[1] = V_Offset + V_Scale*(TopLeft.x - RenderRectangle.x0);
1221 		ExtendedVertexList[2].TexCoord[1] = V_Offset + V_Scale*(BottomRight.x - RenderRectangle.x0);
1222 	}
1223 
1224 	// Fill in remaining points
1225 	// Be sure that the order gives a sidedness the same as
1226 	// that of the world-geometry polygons
1227 	ExtendedVertexList[1].Vertex[0] = ExtendedVertexList[2].Vertex[0];
1228 	ExtendedVertexList[1].Vertex[1] = ExtendedVertexList[0].Vertex[1];
1229 	ExtendedVertexList[1].Vertex[2] = ExtendedVertexList[0].Vertex[2];
1230 	ExtendedVertexList[1].TexCoord[0] = ExtendedVertexList[0].TexCoord[0];
1231 	ExtendedVertexList[1].TexCoord[1] = ExtendedVertexList[2].TexCoord[1];
1232 	ExtendedVertexList[3].Vertex[0] = ExtendedVertexList[0].Vertex[0];
1233 	ExtendedVertexList[3].Vertex[1] = ExtendedVertexList[2].Vertex[1];
1234 	ExtendedVertexList[3].Vertex[2] = ExtendedVertexList[2].Vertex[2];
1235 	ExtendedVertexList[3].TexCoord[0] = ExtendedVertexList[2].TexCoord[0];
1236 	ExtendedVertexList[3].TexCoord[1] = ExtendedVertexList[0].TexCoord[1];
1237 
1238         if(TMgr.IsBlended() || TMgr.TransferMode == _tinted_transfer) {
1239 		glEnable(GL_BLEND);
1240 		setupBlendFunc(TMgr.NormalBlend());
1241 		glEnable(GL_ALPHA_TEST);
1242 		glAlphaFunc(GL_GREATER, 0.001);
1243 	} else {
1244 		glDisable(GL_BLEND);
1245 		glEnable(GL_ALPHA_TEST);
1246 		glAlphaFunc(GL_GREATER, 0.5);
1247 	}
1248 
1249         glDisable(GL_DEPTH_TEST);
1250 
1251 	// Location of data:
1252 	glVertexPointer(3,GL_DOUBLE,sizeof(ExtendedVertexData),ExtendedVertexList[0].Vertex);
1253 	glTexCoordPointer(2,GL_DOUBLE,sizeof(ExtendedVertexData),ExtendedVertexList[0].TexCoord);
1254 	glEnable(GL_TEXTURE_2D);
1255 
1256 	// Go!
1257         glDrawArrays(GL_POLYGON,0,4);
1258 
1259         if (setupGlow(view, TMgr, 0, 1, weaponFlare, selfLuminosity, 0, renderStep)) {
1260             glDrawArrays(GL_QUADS, 0, 4);
1261 	}
1262 
1263 	glEnable(GL_DEPTH_TEST);
1264         Shader::disable();
1265 	TMgr.RestoreTextureMatrix();
1266 
1267 }
1268