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( ¢er, p0, p1 ); // needed for the return value only
442 vm_vec_sub(&reye, &Eye_position, ¢er);
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