1 /*
2  * Code created by Thomas Whittaker (RT) for a FreeSpace 2 source code project
3  *
4  * You may not sell or otherwise commercially exploit the source or things you
5  * created based on the source.
6  *
7 */
8 
9 #include "bmpman/bmpman.h"
10 #include "cmdline/cmdline.h"
11 #include "globalincs/pstypes.h"
12 #include "graphics/2d.h"
13 #include "graphics/grbatch.h"
14 #include "render/3d.h"
15 
~geometry_batcher()16 geometry_batcher::~geometry_batcher()
17 {
18 	if (vert != NULL) {
19 		vm_free(vert);
20 		vert = NULL;
21 	}
22 
23 	if (radius_list != NULL) {
24 		vm_free(radius_list);
25 		radius_list = NULL;
26 	}
27 }
28 
29 /**
30  * Called to start a batch, you make sure you have enough memory
31  * to store all the geometry, then you clear out the memory and set the
32  * number of primitives to 0
33  */
allocate_internal(int n_verts)34 void geometry_batcher::allocate_internal(int n_verts)
35 {
36 
37 	if (n_verts > n_allocated) {
38 		if (vert != NULL) {
39 			vm_free(vert);
40 			vert = NULL;
41 		}
42 
43 		if (radius_list != NULL) {
44 			vm_free(radius_list);
45 			radius_list = NULL;
46 		}
47 
48 		vert = (vertex *) vm_malloc( sizeof(vertex) * n_verts );
49 		radius_list = (float *) vm_malloc( sizeof(float) * n_verts );
50 
51 		Verify( (vert != NULL) );
52 		Verify( (radius_list != NULL) );
53 
54 		memset( vert, 0, sizeof(vertex) * n_verts );
55 		memset( radius_list, 0, sizeof(float) * n_verts );
56 
57 		n_allocated = n_verts;
58 	}
59 
60 	n_to_render = 0;
61 	use_radius = true;
62 }
63 
allocate(int quad,int n_tri)64 void geometry_batcher::allocate(int quad, int n_tri)
65 {
66 	int to_alloc = 0;
67 
68 	// quads have two triangles, therefore six verts
69 	if (quad > 0 ) {
70 		to_alloc += (quad * 6);
71 	}
72 
73 	// a single triangle has a mere 3 verts
74 	if ( n_tri > 0 ) {
75 		to_alloc += (n_tri * 3);
76 	}
77 
78 	allocate_internal(to_alloc);
79 }
80 
add_allocate(int quad,int n_tri)81 void geometry_batcher::add_allocate(int quad, int n_tri)
82 {
83 	int to_alloc = (n_to_render * 3);
84 
85 	// quads have two triangles, therefore six verts
86 	if ( quad > 0 ) {
87 		to_alloc += (quad * 6);
88 	}
89 
90 	// a single triangle has a mere 3 verts
91 	if (n_tri > 0) {
92 		to_alloc += (n_tri * 3);
93 	}
94 
95 	vertex *old_vert = vert;
96 	float *old_radius_list = radius_list;
97 
98 	if (to_alloc > n_allocated) {
99 		vert = (vertex *) vm_malloc( sizeof(vertex) * to_alloc );
100 		radius_list = (float *) vm_malloc( sizeof(float) * to_alloc );
101 
102 		Verify( (vert != NULL) );
103 		Verify( (radius_list != NULL) );
104 
105 		memset( vert, 0, sizeof(vertex) * to_alloc );
106 		memset( radius_list, 0, sizeof(float) * to_alloc );
107 
108 		if (old_vert != NULL) {
109 			memcpy( vert, old_vert, sizeof(vertex) * n_to_render * 3 );
110 			vm_free(old_vert);
111 		}
112 
113 		if (old_radius_list != NULL) {
114 			memcpy( radius_list, old_radius_list, sizeof(float) * n_to_render * 3 );
115 			vm_free(old_radius_list);
116 		}
117 
118 		n_allocated = to_alloc;
119 	}
120 }
121 
clone(const geometry_batcher & geo)122 void geometry_batcher::clone(const geometry_batcher &geo)
123 {
124 	n_to_render = geo.n_to_render;
125 	n_allocated = geo.n_allocated;
126 	use_radius = geo.use_radius;
127 
128 	if (n_allocated > 0) {
129 		vert = (vertex *) vm_malloc( sizeof(vertex) * n_allocated );
130 		radius_list = (float *) vm_malloc( sizeof(float) * n_allocated );
131 
132 		memcpy( vert, geo.vert, sizeof(vertex) * n_allocated );
133 		memcpy( radius_list, geo.radius_list, sizeof(float) * n_allocated);
134 	} else {
135 		vert = NULL;
136 		radius_list = NULL;
137 	}
138 }
139 
operator =(const geometry_batcher & geo)140 geometry_batcher& geometry_batcher::operator=(const geometry_batcher &geo)
141 {
142 	if (this != &geo) {
143 		clone(geo);
144 	}
145 
146 	return *this;
147 }
148 
149 /*
150 0----1
151 |\   |
152 |  \ |
153 3----2
154 */
draw_bitmap(vertex * pnt,int orient,float rad,float depth)155 void geometry_batcher::draw_bitmap(vertex *pnt, int orient, float rad, float depth)
156 {
157 	float radius = rad;
158 	rad *= 1.41421356f;//1/0.707, becase these are the points of a square or width and height rad
159 
160 	vec3d PNT(pnt->world);
161 	vec3d p[4];
162 	vec3d fvec, rvec, uvec;
163 	vertex *P = &vert[n_to_render * 3];
164 	float *R = &radius_list[n_to_render * 3];
165 
166 	// get the direction from the point to the eye
167 	vm_vec_sub(&fvec, &View_position, &PNT);
168 	vm_vec_normalize_safe(&fvec);
169 
170 	// get an up vector in the general direction of what we want
171 	uvec = View_matrix.vec.uvec;
172 
173 	// make a right vector from the f and up vector, this r vec is exactly what we want, so...
174 	vm_vec_cross(&rvec, &View_matrix.vec.fvec, &uvec);
175 	vm_vec_normalize_safe(&rvec);
176 
177 	// fix the u vec with it
178 	vm_vec_cross(&uvec, &View_matrix.vec.fvec, &rvec);
179 
180 	// move the center of the sprite based on the depth parameter
181 	if ( depth != 0.0f )
182 		vm_vec_scale_add(&PNT, &PNT, &fvec, depth);
183 
184 	// move one of the verts to the left
185 	vm_vec_scale_add(&p[0], &PNT, &rvec, rad);
186 
187 	// and one to the right
188 	vm_vec_scale_add(&p[2], &PNT, &rvec, -rad);
189 
190 	// now move all oof the verts to were they need to be
191 	vm_vec_scale_add(&p[1], &p[2], &uvec, rad);
192 	vm_vec_scale_add(&p[3], &p[0], &uvec, -rad);
193 	vm_vec_scale_add(&p[0], &p[0], &uvec, rad);
194 	vm_vec_scale_add(&p[2], &p[2], &uvec, -rad);
195 
196 
197 	//move all the data from the vecs into the verts
198 	//tri 1
199 	g3_transfer_vertex(&P[5], &p[3]);
200 	g3_transfer_vertex(&P[4], &p[2]);
201 	g3_transfer_vertex(&P[3], &p[1]);
202 
203 	//tri 2
204 	g3_transfer_vertex(&P[2], &p[3]);
205 	g3_transfer_vertex(&P[1], &p[1]);
206 	g3_transfer_vertex(&P[0], &p[0]);
207 
208 	// set up the UV coords
209 	if ( orient & 1 ) {
210 		// tri 1
211 		P[5].texture_position.u = 1.0f;
212 		P[4].texture_position.u = 0.0f;
213 		P[3].texture_position.u = 0.0f;
214 
215 		// tri 2
216 		P[2].texture_position.u = 1.0f;
217 		P[1].texture_position.u = 0.0f;
218 		P[0].texture_position.u = 1.0f;
219 	} else {
220 		// tri 1
221 		P[5].texture_position.u = 0.0f;
222 		P[4].texture_position.u = 1.0f;
223 		P[3].texture_position.u = 1.0f;
224 
225 		// tri 2
226 		P[2].texture_position.u = 0.0f;
227 		P[1].texture_position.u = 1.0f;
228 		P[0].texture_position.u = 0.0f;
229 	}
230 
231 	if ( orient & 2 ) {
232 		// tri 1
233 		P[5].texture_position.v = 1.0f;
234 		P[4].texture_position.v = 1.0f;
235 		P[3].texture_position.v = 0.0f;
236 
237 		// tri 2
238 		P[2].texture_position.v = 1.0f;
239 		P[1].texture_position.v = 0.0f;
240 		P[0].texture_position.v = 0.0f;
241 	} else {
242 		// tri 1
243 		P[5].texture_position.v = 0.0f;
244 		P[4].texture_position.v = 0.0f;
245 		P[3].texture_position.v = 1.0f;
246 
247 		// tri 2
248 		P[2].texture_position.v = 0.0f;
249 		P[1].texture_position.v = 1.0f;
250 		P[0].texture_position.v = 1.0f;
251 	}
252 
253 	for (int i = 0; i < 6 ; i++) {
254 		P[i].r = pnt->r;
255 		P[i].g = pnt->g;
256 		P[i].b = pnt->b;
257 		P[i].a = pnt->a;
258 
259 		R[i] = radius;
260 	}
261 
262 	n_to_render += 2;
263 }
264 
draw_bitmap(vertex * pnt,float rad,float angle,float depth)265 void geometry_batcher::draw_bitmap(vertex *pnt, float rad, float angle, float depth)
266 {
267 	float radius = rad;
268 	rad *= 1.41421356f;//1/0.707, becase these are the points of a square or width and height rad
269 
270 	extern float Physics_viewer_bank;
271 	angle -= Physics_viewer_bank;
272 
273 	if ( angle < 0.0f )
274 		angle += PI2;
275 	else if ( angle > PI2 )
276 		angle -= PI2;
277 
278 	vec3d PNT(pnt->world);
279 	vec3d p[4];
280 	vec3d fvec, rvec, uvec;
281 	vertex *P = &vert[n_to_render * 3];
282 	float *R = &radius_list[n_to_render * 3];
283 
284 	vm_vec_sub(&fvec, &View_position, &PNT);
285 	vm_vec_normalize_safe(&fvec);
286 
287 	vm_rot_point_around_line(&uvec, &View_matrix.vec.uvec, angle, &vmd_zero_vector, &View_matrix.vec.fvec);
288 
289 	vm_vec_cross(&rvec, &View_matrix.vec.fvec, &uvec);
290 	vm_vec_normalize_safe(&rvec);
291 	vm_vec_cross(&uvec, &View_matrix.vec.fvec, &rvec);
292 
293 	vm_vec_scale_add(&PNT, &PNT, &fvec, depth);
294 	vm_vec_scale_add(&p[0], &PNT, &rvec, rad);
295 	vm_vec_scale_add(&p[2], &PNT, &rvec, -rad);
296 
297 	vm_vec_scale_add(&p[1], &p[2], &uvec, rad);
298 	vm_vec_scale_add(&p[3], &p[0], &uvec, -rad);
299 	vm_vec_scale_add(&p[0], &p[0], &uvec, rad);
300 	vm_vec_scale_add(&p[2], &p[2], &uvec, -rad);
301 
302 
303 	//move all the data from the vecs into the verts
304 	//tri 1
305 	g3_transfer_vertex(&P[5], &p[3]);
306 	g3_transfer_vertex(&P[4], &p[2]);
307 	g3_transfer_vertex(&P[3], &p[1]);
308 
309 	//tri 2
310 	g3_transfer_vertex(&P[2], &p[3]);
311 	g3_transfer_vertex(&P[1], &p[1]);
312 	g3_transfer_vertex(&P[0], &p[0]);
313 
314 	//tri 1
315 	P[5].texture_position.u = 0.0f;	P[5].texture_position.v = 0.0f;
316 	P[4].texture_position.u = 1.0f;	P[4].texture_position.v = 0.0f;
317 	P[3].texture_position.u = 1.0f;	P[3].texture_position.v = 1.0f;
318 
319 	//tri 2
320 	P[2].texture_position.u = 0.0f;	P[2].texture_position.v = 0.0f;
321 	P[1].texture_position.u = 1.0f;	P[1].texture_position.v = 1.0f;
322 	P[0].texture_position.u = 0.0f;	P[0].texture_position.v = 1.0f;
323 
324 	for (int i = 0; i < 6 ; i++) {
325 		P[i].r = pnt->r;
326 		P[i].g = pnt->g;
327 		P[i].b = pnt->b;
328 		P[i].a = pnt->a;
329 
330 		R[i] = radius;
331 	}
332 
333 	n_to_render += 2;
334 }
335 
draw_tri(vertex * verts)336 void geometry_batcher::draw_tri(vertex* verts)
337 {
338 	vertex *P = &vert[n_to_render *3 ];
339 
340 	for ( int i = 0; i < 3; i++ ) {
341 		P[i] = verts[i];
342 	}
343 
344 	n_to_render += 1;
345 	use_radius = false;
346 }
347 
draw_quad(vertex * verts)348 void geometry_batcher::draw_quad(vertex* verts)
349 {
350 	vertex *P = &vert[n_to_render * 3];
351 
352 	P[0] = verts[0];
353 	P[1] = verts[1];
354 	P[2] = verts[2];
355 
356 	P[3] = verts[0];
357 	P[4] = verts[2];
358 	P[5] = verts[3];
359 
360 	n_to_render += 2;
361 	use_radius = false;
362 }
363 
draw_beam(vec3d * start,vec3d * end,float width,float intensity,float offset)364 void geometry_batcher::draw_beam(vec3d *start, vec3d *end, float width, float intensity, float offset)
365 {
366 	vec3d p[4];
367 	vertex *P = &vert[n_to_render * 3];
368 	float *R = &radius_list[n_to_render * 3];
369 
370 	vec3d fvec, uvecs, uvece, evec;
371 
372 	vm_vec_sub(&fvec, start, end);
373 	vm_vec_normalize_safe(&fvec);
374 
375 	vm_vec_sub(&evec, &View_position, start);
376 	vm_vec_normalize_safe(&evec);
377 
378 	vm_vec_cross(&uvecs, &fvec, &evec);
379 	vm_vec_normalize_safe(&uvecs);
380 
381 	vm_vec_sub(&evec, &View_position, end);
382 	vm_vec_normalize_safe(&evec);
383 
384 	vm_vec_cross(&uvece, &fvec, &evec);
385 	vm_vec_normalize_safe(&uvece);
386 
387 
388 	vm_vec_scale_add(&p[0], start, &uvecs, width);
389 	vm_vec_scale_add(&p[1], end, &uvece, width);
390 	vm_vec_scale_add(&p[2], end, &uvece, -width);
391 	vm_vec_scale_add(&p[3], start, &uvecs, -width);
392 
393 
394 	//move all the data from the vecs into the verts
395 	//tri 1
396 	g3_transfer_vertex(&P[0], &p[3]);
397 	g3_transfer_vertex(&P[1], &p[2]);
398 	g3_transfer_vertex(&P[2], &p[1]);
399 
400 	//tri 2
401 	g3_transfer_vertex(&P[3], &p[3]);
402 	g3_transfer_vertex(&P[4], &p[1]);
403 	g3_transfer_vertex(&P[5], &p[0]);
404 
405 	//set up the UV coords
406 	//tri 1
407 	P[0].texture_position.u = 0.0f;	P[0].texture_position.v = 0.0f;
408 	P[1].texture_position.u = 1.0f;	P[1].texture_position.v = 0.0f;
409 	P[2].texture_position.u = 1.0f;	P[2].texture_position.v = 1.0f;
410 
411 	//tri 2
412 	P[3].texture_position.u = 0.0f;	P[3].texture_position.v = 0.0f;
413 	P[4].texture_position.u = 1.0f;	P[4].texture_position.v = 1.0f;
414 	P[5].texture_position.u = 0.0f;	P[5].texture_position.v = 1.0f;
415 
416 	ubyte _color = (ubyte)(255.0f * intensity);
417 
418 	for(int i = 0; i < 6; i++){
419 		P[i].r = P[i].g = P[i].b = P[i].a = _color;
420 		if(offset > 0.0f) {
421 			R[i] = offset;
422 		} else {
423 			R[i] = width;
424 		}
425 	}
426 
427 	n_to_render += 2;
428 	use_radius = true;
429 }
430 
draw_laser(vec3d * p0,float width1,vec3d * p1,float width2,int r,int g,int b)431 float geometry_batcher::draw_laser(vec3d *p0, float width1, vec3d *p1, float width2, int r, int g, int b)
432 {
433 	width1 *= 0.5f;
434 	width2 *= 0.5f;
435 
436 	vec3d uvec, fvec, rvec, center, reye;
437 
438 	vm_vec_sub( &fvec, p0, p1 );
439 	vm_vec_normalize_safe( &fvec );
440 
441 	vm_vec_avg( &center, p0, p1 ); // needed for the return value only
442 	vm_vec_sub(&reye, &Eye_position, &center);
443 	vm_vec_normalize(&reye);
444 
445 	// compute the up vector
446 	vm_vec_cross(&uvec, &fvec, &reye);
447 	vm_vec_normalize_safe(&uvec);
448 	// ... the forward vector
449 	vm_vec_cross(&fvec, &uvec, &reye);
450 	vm_vec_normalize_safe(&fvec);
451 	// now recompute right vector, in case it wasn't entirely perpendiclar
452 	vm_vec_cross(&rvec, &uvec, &fvec);
453 
454 	// Now have uvec, which is up vector and rvec which is the normal
455 	// of the face.
456 
457 	vec3d start, end;
458 
459 	vm_vec_scale_add(&start, p0, &fvec, -width1);
460 	vm_vec_scale_add(&end, p1, &fvec, width2);
461 
462 	vec3d vecs[4];
463 
464 	vertex *pts = &vert[n_to_render * 3];
465 
466 	vm_vec_scale_add( &vecs[0], &end, &uvec, width2 );
467 	vm_vec_scale_add( &vecs[1], &start, &uvec, width1 );
468 	vm_vec_scale_add( &vecs[2], &start, &uvec, -width1 );
469 	vm_vec_scale_add( &vecs[3], &end, &uvec, -width2 );
470 
471 	g3_transfer_vertex( &pts[0], &vecs[0] );
472 	g3_transfer_vertex( &pts[1], &vecs[1] );
473 	g3_transfer_vertex( &pts[2], &vecs[2] );
474 
475 	g3_transfer_vertex( &pts[3], &vecs[0] );
476 	g3_transfer_vertex( &pts[4], &vecs[2] );
477 	g3_transfer_vertex( &pts[5], &vecs[3] );
478 
479 	pts[0].texture_position.u = 1.0f;
480 	pts[0].texture_position.v = 0.0f;
481 	pts[1].texture_position.u = 0.0f;
482 	pts[1].texture_position.v = 0.0f;
483 	pts[2].texture_position.u = 0.0f;
484 	pts[2].texture_position.v = 1.0f;
485 
486 	pts[3].texture_position.u = 1.0f;
487 	pts[3].texture_position.v = 0.0f;
488 	pts[4].texture_position.u = 0.0f;
489 	pts[4].texture_position.v = 1.0f;
490 	pts[5].texture_position.u = 1.0f;
491 	pts[5].texture_position.v = 1.0f;
492 
493 	pts[0].r = (ubyte)r;
494 	pts[0].g = (ubyte)g;
495 	pts[0].b = (ubyte)b;
496 	pts[0].a = 255;
497 	pts[1].r = (ubyte)r;
498 	pts[1].g = (ubyte)g;
499 	pts[1].b = (ubyte)b;
500 	pts[1].a = 255;
501 	pts[2].r = (ubyte)r;
502 	pts[2].g = (ubyte)g;
503 	pts[2].b = (ubyte)b;
504 	pts[2].a = 255;
505 	pts[3].r = (ubyte)r;
506 	pts[3].g = (ubyte)g;
507 	pts[3].b = (ubyte)b;
508 	pts[3].a = 255;
509 	pts[4].r = (ubyte)r;
510 	pts[4].g = (ubyte)g;
511 	pts[4].b = (ubyte)b;
512 	pts[4].a = 255;
513 	pts[5].r = (ubyte)r;
514 	pts[5].g = (ubyte)g;
515 	pts[5].b = (ubyte)b;
516 	pts[5].a = 255;
517 
518 
519 	n_to_render += 2;
520 	use_radius = false;
521 
522 	return center.xyz.z;
523 }
524 
render(int,float)525 void geometry_batcher::render(int  /*flags*/, float  /*radius*/)
526 {
527 
528 }
529 
load_buffer(effect_vertex * buffer,int * n_verts)530 void geometry_batcher::load_buffer(effect_vertex* buffer, int *n_verts)
531 {
532 	int verts_to_render = n_to_render * 3;
533 	int i;
534 
535 	buffer_offset = *n_verts;
536 
537 	for ( i = 0; i < verts_to_render; ++i) {
538 		buffer[buffer_offset+i].position = vert[i].world;
539 		buffer[buffer_offset+i].tex_coord = vert[i].texture_position;
540 
541 		if ( use_radius && radius_list != NULL ) {
542 			buffer[buffer_offset+i].radius = radius_list[i];
543 		} else {
544 			buffer[buffer_offset+i].radius = 0.0f;
545 		}
546 
547 		buffer[buffer_offset+i].r = vert[i].r;
548 		buffer[buffer_offset+i].g = vert[i].g;
549 		buffer[buffer_offset+i].b = vert[i].b;
550 		buffer[buffer_offset+i].a = vert[i].a;
551 	}
552 
553 	*n_verts = *n_verts + verts_to_render;
554 }
555 
render_buffer(gr_buffer_handle,int)556 void geometry_batcher::render_buffer(gr_buffer_handle  /*buffer_handle*/, int  /*flags*/)
557 {
558 
559 }
560 
render_buffer(gr_buffer_handle,int)561 void geometry_shader_batcher::render_buffer(gr_buffer_handle /*buffer_handle*/, int  /*flags*/)
562 {
563 
564 }
565 
load_buffer(particle_pnt * buffer,size_t * n_verts)566 void geometry_shader_batcher::load_buffer(particle_pnt* buffer, size_t *n_verts)
567 {
568 	size_t verts_to_render = vertices.size();
569 	size_t i;
570 
571 	buffer_offset = *n_verts;
572 
573 	for ( i = 0; i < verts_to_render; ++i) {
574 		buffer[buffer_offset+i] = vertices[i];
575 	}
576 
577 	*n_verts = *n_verts + verts_to_render;
578 }
579 
draw_bitmap(vertex * position,int orient,float rad,float depth)580 void geometry_shader_batcher::draw_bitmap(vertex *position, int orient, float rad, float depth)
581 {
582 	rad *= 1.41421356f;//1/0.707, becase these are the points of a square or width and height rad
583 
584 	vec3d PNT(position->world);
585 	vec3d fvec;
586 
587 	// get the direction from the point to the eye
588 	vm_vec_sub(&fvec, &View_position, &PNT);
589 	vm_vec_normalize_safe(&fvec);
590 
591 	// move the center of the sprite based on the depth parameter
592 	if ( depth != 0.0f )
593 		vm_vec_scale_add(&PNT, &PNT, &fvec, depth);
594 
595 	particle_pnt new_particle;
596 	vec3d up = {{{0.0f, 1.0f, 0.0f}}};
597 
598 	new_particle.position = position->world;
599 	new_particle.size = rad;
600 
601 	int direction = orient % 4;
602 
603 	if ( direction == 1 ) {
604 		up.xyz.x = 0.0f;
605 		up.xyz.y = -1.0f;
606 		up.xyz.z = 0.0f;
607 	} else if ( direction == 2 ) {
608 		up.xyz.x = -1.0f;
609 		up.xyz.y = 0.0f;
610 		up.xyz.z = 0.0f;
611 	} else if ( direction == 3 ) {
612 		up.xyz.x = 1.0f;
613 		up.xyz.y = 0.0f;
614 		up.xyz.z = 0.0f;
615 	}
616 
617 	new_particle.up = up;
618 
619 	vertices.push_back(new_particle);
620 }
621 
622 /**
623  * Laser batcher
624  */
625 struct batch_item {
batch_itembatch_item626 	batch_item(): texture(-1), tmap_flags(0), alpha(1.0f), laser(false) {}
627 
628 	geometry_batcher batch;
629 
630 	int texture;
631 	int tmap_flags;
632 	float alpha;
633 
634 	bool laser;
635 };
636 
637 struct g_sdr_batch_item {
g_sdr_batch_itemg_sdr_batch_item638 	g_sdr_batch_item(): texture(-1), tmap_flags(0), alpha(1.0f), laser(false) {};
639 
640 	geometry_shader_batcher batch;
641 
642 	int texture;
643 	int tmap_flags;
644 	float alpha;
645 
646 	bool laser;
647 };
648 
649 static SCP_map<int, g_sdr_batch_item> geometry_shader_map;
650 static SCP_map<int, batch_item> geometry_map;
651 static SCP_map<int, batch_item> distortion_map;
652 
653 // Used for sending verts to the vertex buffer
654 void *Batch_buffer = NULL;
655 size_t Batch_buffer_size = 0;
656 
657 void *Batch_geometry_buffer = NULL;
658 size_t Batch_geometry_buffer_size = 0;
659 
batch_add_laser(int texture,vec3d * p0,float width1,vec3d * p1,float width2,int r,int g,int b)660 float batch_add_laser(int texture, vec3d *p0, float width1, vec3d *p1, float width2, int r, int g, int b)
661 {
662 	if (texture < 0) {
663 		Int3();
664 		return 1;
665 	}
666 
667 	batch_item *item = NULL;
668 	SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
669 
670 	if (it != geometry_map.end()) {
671 		item = &it->second;
672 	} else {
673 		item = &geometry_map[texture];
674 		item->texture = texture;
675 	}
676 
677 	item->laser = true;
678 
679 	item->batch.add_allocate(1);
680 
681 	float num = item->batch.draw_laser(p0, width1, p1, width2, r, g, b);
682 
683 	return num;
684 }
685 
batch_add_bitmap(int texture,int tmap_flags,vertex * pnt,int orient,float rad,float alpha,float depth)686 int batch_add_bitmap(int texture, int tmap_flags, vertex *pnt, int orient, float rad, float alpha, float depth)
687 {
688 	if (texture < 0) {
689 		Int3();
690 		return 1;
691 	}
692 
693 	if ( tmap_flags & TMAP_FLAG_SOFT_QUAD && !Gr_enable_soft_particles ) {
694 		// don't render this as a soft particle if we don't support soft particles
695 		tmap_flags &= ~(TMAP_FLAG_SOFT_QUAD);
696 	}
697 
698 	if ( Gr_enable_soft_particles && !Cmdline_no_geo_sdr_effects && (tmap_flags & TMAP_FLAG_VERTEX_GEN) ) {
699 		geometry_batch_add_bitmap(texture, tmap_flags, pnt, orient, rad, alpha, depth);
700 		return 0;
701 	} else if ( tmap_flags & TMAP_FLAG_VERTEX_GEN ) {
702 		tmap_flags &= ~(TMAP_FLAG_VERTEX_GEN);
703 	}
704 
705 	batch_item *item = NULL;
706 
707 	SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
708 
709 	if (it != geometry_map.end()) {
710 		item = &it->second;
711 	} else {
712 		item = &geometry_map[texture];
713 		item->texture = texture;
714 	}
715 
716 	Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) );
717 
718 	item->tmap_flags = tmap_flags;
719 	item->alpha = alpha;
720 
721 	item->batch.add_allocate(1);
722 
723 	item->batch.draw_bitmap(pnt, orient, rad, depth);
724 
725 	return 0;
726 }
727 
geometry_batch_add_bitmap(int texture,int tmap_flags,vertex * pnt,int orient,float rad,float alpha,float depth)728 int geometry_batch_add_bitmap(int texture, int tmap_flags, vertex *pnt, int orient, float rad, float alpha, float depth)
729 {
730 	if (texture < 0) {
731 		Int3();
732 		return 1;
733 	}
734 
735 	g_sdr_batch_item *item = NULL;
736 	SCP_map<int, g_sdr_batch_item>::iterator it = geometry_shader_map.find(texture);
737 
738 	if (it != geometry_shader_map.end()) {
739 		item = &it->second;
740 	} else {
741 		item = &geometry_shader_map[texture];
742 		item->texture = texture;
743 	}
744 
745 	Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) );
746 
747 	item->tmap_flags = tmap_flags;
748 	item->alpha = alpha;
749 
750 	item->batch.draw_bitmap(pnt, orient, rad, depth);
751 
752 	return 0;
753 }
754 
batch_add_bitmap_rotated(int texture,int tmap_flags,vertex * pnt,float angle,float rad,float alpha,float depth)755 int batch_add_bitmap_rotated(int texture, int tmap_flags, vertex *pnt, float angle, float rad, float alpha, float depth)
756 {
757 	if (texture < 0) {
758 		Int3();
759 		return 1;
760 	}
761 
762 	if ( tmap_flags & TMAP_FLAG_SOFT_QUAD && !Gr_enable_soft_particles ) {
763 		// don't render this as a soft particle if we don't support soft particles
764 		tmap_flags &= ~(TMAP_FLAG_SOFT_QUAD);
765 	}
766 
767 	batch_item *item = NULL;
768 
769 	SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
770 
771 	if (it != geometry_map.end()) {
772 		item = &it->second;
773 	} else {
774 		item = &geometry_map[texture];
775 		item->texture = texture;
776 	}
777 
778 	Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) );
779 
780 	item->tmap_flags = tmap_flags;
781 	item->alpha = alpha;
782 
783 	item->batch.add_allocate(1);
784 
785 	item->batch.draw_bitmap(pnt, rad, angle, depth);
786 
787 	return 0;
788 }
789 
batch_add_tri(int texture,int tmap_flags,vertex * verts,float alpha)790 int batch_add_tri(int texture, int tmap_flags, vertex *verts, float alpha)
791 {
792 	if (texture < 0) {
793 		Int3();
794 		return 1;
795 	}
796 
797 	batch_item *item = NULL;
798 
799 	SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
800 
801 	if (it != geometry_map.end()) {
802 		item = &it->second;
803 	} else {
804 		item = &geometry_map[texture];
805 		item->texture = texture;
806 	}
807 
808 	Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) );
809 
810 	item->tmap_flags = tmap_flags;
811 	item->alpha = alpha;
812 
813 	item->batch.add_allocate(0, 1);	// just allocating for one triangle
814 
815 	item->batch.draw_tri(verts);
816 
817 	return 0;
818 }
819 
batch_add_quad(int texture,int tmap_flags,vertex * verts,float alpha)820 int batch_add_quad(int texture, int tmap_flags, vertex *verts, float alpha)
821 {
822 	if (texture < 0) {
823 		Int3();
824 		return 1;
825 	}
826 
827 	batch_item *item = NULL;
828 
829 	SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
830 
831 	if (it != geometry_map.end()) {
832 		item = &it->second;
833 	} else {
834 		item = &geometry_map[texture];
835 		item->texture = texture;
836 	}
837 
838 	Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) );
839 
840 	item->tmap_flags = tmap_flags;
841 	item->alpha = alpha;
842 
843 	item->batch.add_allocate(1);
844 
845 	item->batch.draw_quad(verts);
846 
847 	return 0;
848 }
849 
batch_add_polygon(int texture,int tmap_flags,vec3d * pos,matrix * orient,float width,float height,float alpha)850 int batch_add_polygon(int texture, int tmap_flags, vec3d *pos, matrix *orient, float width, float height, float alpha)
851 {
852 	//idiot-proof
853 	if(width == 0 || height == 0)
854 		return 0;
855 
856 	Assert(pos != NULL);
857 	Assert(orient != NULL);
858 
859 	//Let's begin.
860 
861 	const int NUM_VERTICES = 4;
862 	vec3d p[NUM_VERTICES] = { ZERO_VECTOR };
863 	vertex v[NUM_VERTICES] = { vertex() };
864 
865 	p[0].xyz.x = width;
866 	p[0].xyz.y = height;
867 
868 	p[1].xyz.x = -width;
869 	p[1].xyz.y = height;
870 
871 	p[2].xyz.x = -width;
872 	p[2].xyz.y = -height;
873 
874 	p[3].xyz.x = width;
875 	p[3].xyz.y = -height;
876 
877 	for(int i = 0; i < NUM_VERTICES; i++)
878 	{
879 		vec3d tmp = vmd_zero_vector;
880 
881 		//Rotate correctly
882 		vm_vec_unrotate(&tmp, &p[i], orient);
883 		//Move to point in space
884 		vm_vec_add2(&tmp, pos);
885 
886 		//Convert to vertex
887 		g3_transfer_vertex(&v[i], &tmp);
888 	}
889 
890 	v[0].texture_position.u = 1.0f;
891 	v[0].texture_position.v = 0.0f;
892 
893 	v[1].texture_position.u = 0.0f;
894 	v[1].texture_position.v = 0.0f;
895 
896 	v[2].texture_position.u = 0.0f;
897 	v[2].texture_position.v = 1.0f;
898 
899 	v[3].texture_position.u = 1.0f;
900 	v[3].texture_position.v = 1.0f;
901 
902 	if (texture < 0) {
903 		Int3();
904 		return 1;
905 	}
906 
907 	batch_item *item = NULL;
908 
909 	SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
910 
911 	if (it != geometry_map.end()) {
912 		item = &it->second;
913 	} else {
914 		item = &geometry_map[texture];
915 		item->texture = texture;
916 	}
917 
918 	Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) );
919 
920 	item->tmap_flags = tmap_flags;
921 	item->alpha = alpha;
922 
923 	item->batch.add_allocate(1);
924 
925 	item->batch.draw_quad(v);
926 
927 	return 0;
928 }
929 
batch_add_beam(int texture,int tmap_flags,vec3d * start,vec3d * end,float width,float intensity)930 int batch_add_beam(int texture, int tmap_flags, vec3d *start, vec3d *end, float width, float intensity)
931 {
932 	if (texture < 0) {
933 		Int3();
934 		return 1;
935 	}
936 
937 	batch_item *item = NULL;
938 
939 	SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
940 
941 	if (it != geometry_map.end()) {
942 		item = &it->second;
943 	} else {
944 		item = &geometry_map[texture];
945 		item->texture = texture;
946 	}
947 
948 	Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) );
949 
950 	item->tmap_flags = tmap_flags;
951 	item->alpha = intensity;
952 
953 	item->batch.add_allocate(1);
954 
955 	item->batch.draw_beam(start, end, width, intensity);
956 
957 	return 0;
958 }
959 
batch_render_lasers(gr_buffer_handle buffer_handle)960 void batch_render_lasers(gr_buffer_handle buffer_handle)
961 {
962 	for (auto &bi : geometry_map) {
963 
964 		if ( !bi.second.laser )
965 			continue;
966 
967 		if ( !bi.second.batch.need_to_render() )
968 			continue;
969 
970 		Assert( bi.second.texture >= 0 );
971 		gr_set_bitmap(bi.second.texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.99999f);
972 		if (buffer_handle.isValid()) {
973 			bi.second.batch.render_buffer(buffer_handle, TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_HTL_3D_UNLIT | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT | TMAP_FLAG_EMISSIVE);
974 		} else {
975 			bi.second.batch.render(TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_HTL_3D_UNLIT | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT | TMAP_FLAG_EMISSIVE);
976 		}
977 	}
978 }
979 
batch_load_buffer_lasers(effect_vertex * buffer,int * n_verts)980 void batch_load_buffer_lasers(effect_vertex* buffer, int *n_verts)
981 {
982 	for (auto &bi : geometry_map) {
983 
984 		if ( !bi.second.laser )
985 			continue;
986 
987 		if ( !bi.second.batch.need_to_render() )
988 			continue;
989 
990 		Assert( bi.second.texture >= 0 );
991 		bi.second.batch.load_buffer(buffer, n_verts);
992 	}
993 }
994 
batch_render_geometry_map_bitmaps(gr_buffer_handle buffer_handle)995 void batch_render_geometry_map_bitmaps(gr_buffer_handle buffer_handle)
996 {
997 	for (auto &bi : geometry_map) {
998 
999 		if ( bi.second.laser )
1000 			continue;
1001 
1002 		if ( !bi.second.batch.need_to_render() )
1003 			continue;
1004 
1005 		Assert( bi.second.texture >= 0 );
1006 		gr_set_bitmap(bi.second.texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, bi.second.alpha);
1007 		if (buffer_handle.isValid()) {
1008 			bi.second.batch.render_buffer(buffer_handle, bi.second.tmap_flags);
1009 		} else {
1010 			bi.second.batch.render( bi.second.tmap_flags);
1011 		}
1012 	}
1013 }
1014 
batch_render_geometry_shader_map_bitmaps(gr_buffer_handle buffer_handle)1015 void batch_render_geometry_shader_map_bitmaps(gr_buffer_handle buffer_handle)
1016 {
1017 	for (auto &bi : geometry_shader_map) {
1018 
1019 		if ( bi.second.laser )
1020 			continue;
1021 
1022 		if ( !bi.second.batch.need_to_render() )
1023 			continue;
1024 
1025 		Assert( bi.second.texture >= 0 );
1026 		gr_set_bitmap(bi.second.texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, bi.second.alpha);
1027 		bi.second.batch.render_buffer(buffer_handle, bi.second.tmap_flags);
1028 	}
1029 }
1030 
batch_load_buffer_geometry_map_bitmaps(effect_vertex * buffer,int * n_verts)1031 void batch_load_buffer_geometry_map_bitmaps(effect_vertex* buffer, int *n_verts)
1032 {
1033 	for (auto &bi : geometry_map) {
1034 
1035 		if ( bi.second.laser )
1036 			continue;
1037 
1038 		if ( !bi.second.batch.need_to_render() )
1039 			continue;
1040 
1041 		Assert( bi.second.texture >= 0 );
1042 		bi.second.batch.load_buffer(buffer, n_verts);
1043 	}
1044 }
1045 
batch_load_buffer_geometry_shader_map_bitmaps(particle_pnt * buffer,size_t * n_verts)1046 void batch_load_buffer_geometry_shader_map_bitmaps(particle_pnt* buffer, size_t *n_verts)
1047 {
1048 	for (auto &bi : geometry_shader_map) {
1049 
1050 		if ( bi.second.laser )
1051 			continue;
1052 
1053 		if ( !bi.second.batch.need_to_render() )
1054 			continue;
1055 
1056 		Assert( bi.second.texture >= 0 );
1057 		bi.second.batch.load_buffer(buffer, n_verts);
1058 	}
1059 }
1060 
geometry_batch_render(gr_buffer_handle stream_buffer)1061 void geometry_batch_render(gr_buffer_handle stream_buffer)
1062 {
1063 	if (!stream_buffer.isValid()) {
1064 		return;
1065 	}
1066 
1067 	size_t n_to_render = geometry_batch_get_size();
1068 	size_t n_verts = 0;
1069 
1070 	if ( Batch_geometry_buffer_size < (n_to_render * sizeof(particle_pnt)) ) {
1071 		if ( Batch_geometry_buffer != NULL ) {
1072 			vm_free(Batch_geometry_buffer);
1073 		}
1074 
1075 		Batch_geometry_buffer_size = n_to_render * sizeof(particle_pnt);
1076 		Batch_geometry_buffer = vm_malloc(Batch_geometry_buffer_size);
1077 	}
1078 
1079 	batch_load_buffer_geometry_shader_map_bitmaps((particle_pnt*)Batch_geometry_buffer, &n_verts);
1080 
1081 	gr_update_buffer_data(stream_buffer, Batch_geometry_buffer_size, Batch_geometry_buffer);
1082 
1083 	batch_render_geometry_shader_map_bitmaps(stream_buffer);
1084 }
1085 
batch_render_all(gr_buffer_handle stream_buffer)1086 void batch_render_all(gr_buffer_handle stream_buffer)
1087 {
1088 	if (stream_buffer.isValid()) {
1089 		// need to get vertex size
1090 		int n_to_render = batch_get_size();
1091 		int n_verts = 0;
1092 
1093 		if ( ( Batch_buffer_size < (n_to_render * sizeof(effect_vertex)) ) ) {
1094 			if ( Batch_buffer != NULL ) {
1095 				vm_free(Batch_buffer);
1096 			}
1097 
1098 			Batch_buffer_size = n_to_render * sizeof(effect_vertex);
1099 			Batch_buffer = vm_malloc(Batch_buffer_size);
1100 		}
1101 
1102 		batch_load_buffer_lasers((effect_vertex*)Batch_buffer, &n_verts);
1103 		batch_load_buffer_geometry_map_bitmaps((effect_vertex*)Batch_buffer, &n_verts);
1104 		batch_load_buffer_distortion_map_bitmaps((effect_vertex*)Batch_buffer, &n_verts);
1105 		gr_update_buffer_data(stream_buffer, Batch_buffer_size, Batch_buffer);
1106 
1107 		Assert(n_verts <= n_to_render);
1108 
1109 		batch_render_lasers(stream_buffer);
1110 		batch_render_geometry_map_bitmaps(stream_buffer);
1111 		//batch_render_distortion_map_bitmaps(true);
1112 	} else {
1113 		batch_render_lasers();
1114 		batch_render_geometry_map_bitmaps();
1115 		//batch_render_distortion_map_bitmaps();
1116 	}
1117 
1118 	gr_clear_states();
1119 }
1120 
batch_reset()1121 void batch_reset()
1122 {
1123 	geometry_map.clear();
1124 	distortion_map.clear();
1125 }
1126 
batch_render_close()1127 void batch_render_close()
1128 {
1129 	if ( Batch_buffer != NULL ) {
1130 		vm_free(Batch_buffer);
1131 		Batch_buffer = NULL;
1132 	}
1133 
1134 	Batch_buffer_size = 0;
1135 }
1136 
distortion_add_bitmap_rotated(int texture,int tmap_flags,vertex * pnt,float angle,float rad,float alpha,float depth)1137 int distortion_add_bitmap_rotated(int texture, int tmap_flags, vertex *pnt, float angle, float rad, float alpha, float depth)
1138 {
1139 	if (texture < 0) {
1140 		Int3();
1141 		return 1;
1142 	}
1143 
1144 	batch_item *item = NULL;
1145 
1146 	SCP_map<int, batch_item>::iterator it = distortion_map.find(texture);
1147 
1148 	if (it != distortion_map.end()) {
1149 		item = &it->second;
1150 	} else {
1151 		item = &distortion_map[texture];
1152 		item->texture = texture;
1153 	}
1154 
1155 	Assertion( (item->laser == false), "Distortion particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) );
1156 
1157 	item->tmap_flags = tmap_flags;
1158 	item->alpha = alpha;
1159 
1160 	item->batch.add_allocate(1);
1161 
1162 	item->batch.draw_bitmap(pnt, rad, angle, depth);
1163 
1164 	return 0;
1165 }
1166 
distortion_add_beam(int texture,int tmap_flags,vec3d * start,vec3d * end,float width,float intensity,float offset)1167 int distortion_add_beam(int texture, int tmap_flags, vec3d *start, vec3d *end, float width, float intensity, float offset)
1168 {
1169 	if (texture < 0) {
1170 		Int3();
1171 		return 1;
1172 	}
1173 
1174 	batch_item *item = NULL;
1175 
1176 	SCP_map<int, batch_item>::iterator it = distortion_map.find(texture);
1177 
1178 	if (it != distortion_map.end()) {
1179 		item = &it->second;
1180 	} else {
1181 		item = &distortion_map[texture];
1182 		item->texture = texture;
1183 	}
1184 
1185 	Assertion( (item->laser == false), "Distortion particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) );
1186 
1187 	item->tmap_flags = tmap_flags;
1188 	item->alpha = intensity;
1189 
1190 	item->batch.add_allocate(1);
1191 
1192 	item->batch.draw_beam(start,end,width,intensity,offset);
1193 
1194 	return 0;
1195 }
1196 
batch_render_distortion_map_bitmaps(gr_buffer_handle buffer_handle)1197 void batch_render_distortion_map_bitmaps(gr_buffer_handle buffer_handle)
1198 {
1199 	for (auto &bi : distortion_map) {
1200 
1201 		if ( bi.second.laser )
1202 			continue;
1203 
1204 		if ( !bi.second.batch.need_to_render() )
1205 			continue;
1206 
1207 		Assert( bi.second.texture >= 0 );
1208 		gr_set_bitmap(bi.second.texture, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, bi.second.alpha);
1209 
1210 		if (buffer_handle.isValid()) {
1211 			bi.second.batch.render_buffer(buffer_handle, bi.second.tmap_flags);
1212 		} else {
1213 			bi.second.batch.render( bi.second.tmap_flags);
1214 		}
1215 	}
1216 }
1217 
batch_load_buffer_distortion_map_bitmaps(effect_vertex * buffer,int * n_verts)1218 void batch_load_buffer_distortion_map_bitmaps(effect_vertex* buffer, int *n_verts)
1219 {
1220 	for (auto &bi : distortion_map) {
1221 
1222 		if ( bi.second.laser )
1223 			continue;
1224 
1225 		if ( !bi.second.batch.need_to_render() )
1226 			continue;
1227 
1228 		Assert( bi.second.texture >= 0 );
1229 		bi.second.batch.load_buffer(buffer, n_verts);
1230 	}
1231 }
1232 
batch_get_size()1233 int batch_get_size()
1234 {
1235 	int n_to_render = 0;
1236 
1237 	for (auto &bi : geometry_map) {
1238 		n_to_render += bi.second.batch.need_to_render();
1239 	}
1240 
1241 	for (auto &bi : distortion_map) {
1242 		if ( bi.second.laser )
1243 			continue;
1244 
1245 		n_to_render += bi.second.batch.need_to_render();
1246 	}
1247 
1248 	return n_to_render * 3;
1249 }
1250 
geometry_batch_get_size()1251 size_t geometry_batch_get_size()
1252 {
1253 	size_t n_to_render = 0;
1254 
1255 	for (auto &bi : geometry_shader_map) {
1256 		n_to_render += bi.second.batch.need_to_render();
1257 	}
1258 
1259 	return n_to_render;
1260 }
1261