/* * Code created by Thomas Whittaker (RT) for a Freespace 2 source code project * * You may not sell or otherwise commercially exploit the source or things you * created based on the source. * */ #include #include "globalincs/pstypes.h" #include "graphics/grbatch.h" #include "graphics/2d.h" #include "cmdline/cmdline.h" #include "render/3d.h" typedef struct { int start, length; int flags; int bitmap; } BatchNode; const int BATCH_MAX_VERTEX = 500; const int BATCH_MAX = 50; vertex *Batch_vertex_array = NULL; BatchNode *Batch_array = NULL; bool Batch_in_process = false; int Batch_current = 0; int Batch_vertex_current = 0; bool batch_init() { if(!Cmdline_batch_3dunlit) return true; Batch_vertex_array = (vertex *) malloc(sizeof(vertex) * BATCH_MAX_VERTEX); Batch_array = (BatchNode *) malloc(sizeof(vertex) * BATCH_MAX); return (Batch_array != 0); } void batch_deinit() { if(!Cmdline_batch_3dunlit) return; if (Batch_array != NULL) { free(Batch_array); Batch_array = NULL; } if (Batch_vertex_array != NULL) { free(Batch_vertex_array); Batch_vertex_array = NULL; } } void batch_start() { Batch_in_process = true; Batch_current = 0; Batch_vertex_current = 0; } void batch_end() { Batch_in_process = false; } void batch_render() { if(!Cmdline_batch_3dunlit) return; if(Batch_current == 0) return; // Sort // Batch up again // Send to renderer for(int i = 0; i < Batch_current; i++) { vertex *vlist = &Batch_vertex_array[Batch_array[i].start]; gr_set_bitmap(Batch_array[i].bitmap); gr_tmapper_batch_3d_unlit(Batch_array[i].length, vlist, Batch_array[i].flags); } Batch_current = 0; Batch_vertex_current = 0; } vertex *batch_get_block(int num_verts, int flags) { if(!Cmdline_batch_3dunlit) return NULL; if(Batch_vertex_array == NULL || Batch_array == NULL) { Assert(0); return NULL; } //int vcurrent = 0; // We've run out of vertex slots! if(num_verts >= (BATCH_MAX_VERTEX - Batch_vertex_current)) { batch_render(); } // Not the first batch if(Batch_current > 0) { int last_batch = Batch_current - 1; // Can add to current batch if( Batch_array[last_batch].flags == flags && Batch_array[last_batch].bitmap == gr_screen.current_bitmap) { int pos = Batch_array[last_batch].start + Batch_array[last_batch].length; vertex *block = &Batch_vertex_array[pos]; Batch_array[last_batch].length += num_verts; Batch_vertex_current += num_verts; return block; } } // We've run out of batch slots! if(Batch_current >= BATCH_MAX) { batch_render(); } // Make a new batch Batch_array[Batch_current].flags = flags; Batch_array[Batch_current].start = Batch_vertex_current; Batch_array[Batch_current].length = num_verts; Batch_array[Batch_current].bitmap = gr_screen.current_bitmap; vertex *block = &Batch_vertex_array[Batch_array[Batch_current].start]; Batch_current++; Batch_vertex_current += num_verts; return block; } //I noticed this file after implementing this, and figured it would be better to put my batcher in here -Bobboau /* class geometry_batcher{ int n_to_render; int n_allocated; vertex* vert; vertex** vert_list;//V's stupid rendering functions need this } */ void geometry_batcher::allocate_internal(int n_verts){ //this is called to start a batch, you make sure you have enough memory //to store all the geometry, //then you clear out the memory and set the number of primitives to 0 if(n_verts>n_allocated){ if(vert)free(vert); if(vert_list)free(vert_list); vert = (vertex*)malloc(sizeof(vertex)*n_verts); vert_list = (vertex**)malloc(sizeof(vertex*)*n_verts); for(int i = 0; in_allocated){ if(vert_list)free(vert_list); vert = (vertex*)malloc(sizeof(vertex)*to_aloc); vert_list = (vertex**)malloc(sizeof(vertex*)*to_aloc); for(int i = 0; ir; P[i].g = pnt->g; P[i].b = pnt->b; P[i].a = pnt->a; } n_to_render += 2; } void geometry_batcher::draw_bitmap(vertex *pnt, float rad, float angle, float depth){ rad *= 1.41421356f;//1/0.707, becase these are the points of a square or width and hieght rad extern float Physics_viewer_bank; angle+=Physics_viewer_bank; if ( angle < 0.0f ) angle += PI2; else if ( angle > PI2 ) angle -= PI2; vec3d PNT; vm_vert2vec(pnt, &PNT); vec3d p[4]; vertex *P = &vert[n_to_render*3]; vec3d fvec, rvec, uvec; vm_vec_sub(&fvec, &View_position, &PNT); vm_vec_normalize(&fvec); vm_rot_point_around_line(&uvec, &View_matrix.vec.uvec, angle, &vmd_zero_vector, &fvec); // uvec = View_matrix.vec.uvec; vm_vec_crossprod(&rvec, &fvec, &uvec); vm_vec_normalize(&rvec); vm_vec_crossprod(&uvec, &fvec, &rvec); vm_vec_scale_add(&PNT, &PNT, &fvec, depth); vm_vec_scale_add(&p[0], &PNT, &rvec, rad); vm_vec_scale_add(&p[2], &PNT, &rvec, -rad); vm_vec_scale_add(&p[1], &p[2], &uvec, rad); vm_vec_scale_add(&p[3], &p[0], &uvec, -rad); vm_vec_scale_add(&p[0], &p[0], &uvec, rad); vm_vec_scale_add(&p[2], &p[2], &uvec, -rad); //move all the data from the vecs into the verts //tri 1 g3_transfer_vertex(&P[5], &p[3]); g3_transfer_vertex(&P[4], &p[2]); g3_transfer_vertex(&P[3], &p[1]); //tri 2 g3_transfer_vertex(&P[2], &p[3]); g3_transfer_vertex(&P[1], &p[1]); g3_transfer_vertex(&P[0], &p[0]); //set up the UV coords //tri 1 P[5].u = 0.0f; P[5].v = 0.0f; P[4].u = 1.0f; P[4].v = 0.0f; P[3].u = 1.0f; P[3].v = 1.0f; //tri 2 P[2].u = 0.0f; P[2].v = 0.0f; P[1].u = 1.0f; P[1].v = 1.0f; P[0].u = 0.0f; P[0].v = 1.0f; for(int i = 0; i<6 ; i++){ P[i].r = pnt->r; P[i].g = pnt->g; P[i].b = pnt->b; P[i].a = pnt->a; } n_to_render += 2; } void geometry_batcher::draw_tri(vertex* verts){ vertex *P = &vert[n_to_render*3]; for(int i = 0; i<3; i++) P[i] = verts[i]; n_to_render += 1; } void geometry_batcher::draw_quad(vertex* verts){ vertex *P = &vert[n_to_render*3]; P[0] = verts[0]; P[1] = verts[1]; P[2] = verts[2]; P[0] = verts[0]; P[2] = verts[2]; P[3] = verts[3]; n_to_render += 2; } void geometry_batcher::draw_beam(vec3d*start,vec3d*end, float width, float intinsity){ vec3d p[4]; vertex *P = &vert[n_to_render*3]; vec3d fvec, uvecs, uvece, evec; vm_vec_sub(&fvec, end, start); vm_vec_normalize(&fvec); vm_vec_sub(&evec, &View_position, start); vm_vec_normalize(&evec); vm_vec_crossprod(&uvecs, &evec, &fvec); vm_vec_sub(&evec, &View_position, end); vm_vec_normalize(&evec); vm_vec_crossprod(&uvece, &evec, &fvec); vm_vec_scale_add(&p[0], start, &uvecs, width); vm_vec_scale_add(&p[1], end, &uvece, width); vm_vec_scale_add(&p[2], end, &uvece, -width); vm_vec_scale_add(&p[3], start, &uvecs, -width); //move all the data from the vecs into the verts //tri 1 g3_transfer_vertex(&P[0], &p[3]); g3_transfer_vertex(&P[1], &p[2]); g3_transfer_vertex(&P[2], &p[1]); //tri 2 g3_transfer_vertex(&P[3], &p[3]); g3_transfer_vertex(&P[4], &p[1]); g3_transfer_vertex(&P[5], &p[0]); //set up the UV coords //tri 1 P[0].u = 0.0f; P[0].v = 0.0f; P[1].u = 1.0f; P[1].v = 0.0f; P[2].u = 1.0f; P[2].v = 1.0f; //tri 2 P[3].u = 0.0f; P[3].v = 0.0f; P[4].u = 1.0f; P[4].v = 1.0f; P[5].u = 0.0f; P[5].v = 1.0f; for(int i = 0; i<6 ; i++){ P[i].r = (ubyte)(255.0f * intinsity); P[i].g = (ubyte)(255.0f * intinsity); P[i].b = (ubyte)(255.0f * intinsity); P[i].a = (ubyte)(255.0f * intinsity); } n_to_render += 2; } float geometry_batcher::draw_laser(vec3d *p0,float width1,vec3d *p1,float width2, int r, int g, int b){ width1 *= 0.5f; width2 *= 0.5f; vec3d uvec, fvec, rvec, center, reye; vm_vec_sub( &fvec, p0, p1 ); vm_vec_normalize_safe( &fvec ); vm_vec_avg( ¢er, p0, p1 ); //needed for the return value only vm_vec_sub(&reye, &Eye_position, ¢er); vm_vec_normalize(&reye); vm_vec_crossprod(&uvec,&fvec,&reye); vm_vec_normalize(&uvec); vm_vec_crossprod(&fvec,&uvec,&reye); vm_vec_normalize(&fvec); //now recompute right vector, in case it wasn't entirely perpendiclar vm_vec_crossprod(&rvec,&uvec,&fvec); // Now have uvec, which is up vector and rvec which is the normal // of the face. vec3d start, end; vm_vec_scale_add(&start, p0, &fvec, -width1); vm_vec_scale_add(&end, p1, &fvec, width2); vec3d vecs[4]; vertex *pts = &vert[n_to_render*3]; vm_vec_scale_add( &vecs[0], &end, &uvec, width2 ); vm_vec_scale_add( &vecs[1], &start, &uvec, width1 ); vm_vec_scale_add( &vecs[2], &start, &uvec, -width1 ); vm_vec_scale_add( &vecs[3], &end, &uvec, -width2 ); g3_transfer_vertex( &pts[0], &vecs[0] ); g3_transfer_vertex( &pts[1], &vecs[1] ); g3_transfer_vertex( &pts[2], &vecs[2] ); g3_transfer_vertex( &pts[3], &vecs[0] ); g3_transfer_vertex( &pts[4], &vecs[2] ); g3_transfer_vertex( &pts[5], &vecs[3] ); pts[0].u = 1.0f; pts[0].v = 0.0f; pts[1].u = 0.0f; pts[1].v = 0.0f; pts[2].u = 0.0f; pts[2].v = 1.0f; pts[3].u = 1.0f; pts[3].v = 0.0f; pts[4].u = 0.0f; pts[4].v = 1.0f; pts[5].u = 1.0f; pts[5].v = 1.0f; pts[0].r = (ubyte)r; pts[0].g = (ubyte)g; pts[0].b = (ubyte)b; pts[0].a = 255; pts[1].r = (ubyte)r; pts[1].g = (ubyte)g; pts[1].b = (ubyte)b; pts[1].a = 255; pts[2].r = (ubyte)r; pts[2].g = (ubyte)g; pts[2].b = (ubyte)b; pts[2].a = 255; pts[3].r = (ubyte)r; pts[3].g = (ubyte)g; pts[3].b = (ubyte)b; pts[3].a = 255; pts[4].r = (ubyte)r; pts[4].g = (ubyte)g; pts[4].b = (ubyte)b; pts[4].a = 255; pts[5].r = (ubyte)r; pts[5].g = (ubyte)g; pts[5].b = (ubyte)b; pts[5].a = 255; n_to_render += 2; return center.xyz.z; } void geometry_batcher::render(int flags){ // gr_set_cull(0); if(n_to_render) g3_draw_poly( n_to_render*3, vert_list, flags | TMAP_FLAG_TRILIST); n_to_render = 0; } //laser batcher #define MAX_LASER_TYPES 256 batch_item geometry_map[MAX_LASER_TYPES]; int find_good_batch_item(int texture){ //I realy doubt there will be more than 12 or so of these //this could probly be sped up by reseting it every mission for(int i = 0; iadd_alocate(1); return item->draw_laser(p0, width1, p1, width2, r,g,b); return 0; } void batch_render_lasers(){ for (int i = 0; geometry_map[i].texture != -1; i++){ gr_set_bitmap(geometry_map[i].texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.99999f); geometry_map[i].batch.render(TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_HTL_3D_UNLIT | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT); } }