mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-10 04:31:34 -10:00
fix some compiler warning messages don't do any decal processing if decals are disabled, the math was a waste of CPU cycles in that case
2231 lines
70 KiB
C++
2231 lines
70 KiB
C++
//sorce file for decals-Bobboau
|
|
//and no, I don't have any idea what I'm doing
|
|
|
|
/*
|
|
DECAL AND POLYGON MANAGEMENT:
|
|
|
|
High Level Decal Management
|
|
the decals are organised by texture into lists, they are held in the ship structure by a
|
|
dynamic array of decal_list_controle items wich, as the name sudgests, controle a decal list.
|
|
the decal_list_controle has the first element of a linked list of decals and the last element
|
|
for easy adding to the end. it also keeps trak of the texture(s) to be used wich vertex buffer
|
|
is assosiated with the decals under it's controle, and manages decal book keeping (adding/trimming).
|
|
each ship has a set number of decals can be within each list, and once that number is
|
|
exceeded it begins recycleing the oldest decal in the list. allocation of a new decal is
|
|
provided by the 'decal_find_next' function, you tell it wich texture and wich ship the new
|
|
decal is going to use and it find/allocate/does whatever it has to to get you a decal.
|
|
|
|
Low Level Decal Management
|
|
origonaly I made use of dynamic memory, this was a bad idea, slow as all hell. so after
|
|
some thinking, I devised a static memory allocation system for both decals and the polys
|
|
within them. for each of them there is a staticly allocated arry 'big_ol_decal_array' and
|
|
'big_ol_decal_poly_array' respectively. the function 'get_open_decal_list' has the job of
|
|
looking through the big_ol_decal_array and finding a decal that has not yet been claimed
|
|
(or has been freed from it's former tyrantical master (a decal) ), it then returns a pointer
|
|
to this elementwich is added onto the end of a decal list. there are MAX_GLOBAL_DECALS decals
|
|
available, at the time of this documentation MAX_GLOBAL_DECALS is defined as 5000, I don't
|
|
think it would ever use that many in it's current form though as the most decals any capship
|
|
would have would probly be 700, and there's rarely more than two or three at a time, fighters
|
|
would only rack up about 10-20 before dieing, and the medium sized ship would fall some were
|
|
between them (100-300). so the lookup of decals from the static memory block is a simple for
|
|
loop that checks a 'used' flag, and the first one it finds it returns.
|
|
there is also a secondary list for burn maps, this is a second pass that renders a glowing burn texture over fresh decals
|
|
in each decal there is a list of polygons (triangles) grabed from a similar global array,
|
|
they are held in a linked list within each decal (you may be confused by the use of linked
|
|
lists within an array the array simply serves as a giant block of allocated memory, outside
|
|
of the management functions it is never used directly)
|
|
polygon mamagement is on the other hand signifigant enough to warent it's own section.
|
|
|
|
Low Level Polygon Management
|
|
initaly I thought of useing a similar simple lookup system as thedecal management, but the
|
|
lookup of polygons is both more frequent (about a dozen times per created decal) and more
|
|
intinsive (there are MAX_GLOBAL_DECAL_POLYS to sort through, at the time of documentation
|
|
this was defined as _11000_ !). I had to devise something a bit more clever. the big_ol_decal_poly_array
|
|
is subdivided into (QUICKFIND_SUBDIVISION == 100) segments, each segment has a length
|
|
determined to be (MAX_GLOBAL_DECAL_POLYS/QUICKFIND_SUBDIVISION) aka QUICKFIND_SEGMENT_LENGTH.
|
|
wich is 110 for anyone who may care I made a paralel array for each of these segments called
|
|
'quick_find_array' looking in the elements of this array I can determine weather I should
|
|
bother looking at any of the elements of big_ol_decal_poly_array within the segment that
|
|
quick_find_array represents, this turns what would be a potentaly 11000 element search
|
|
into no more than 210 (QUICKFIND_SUBDIVISION + QUICKFIND_SEGMENT_LENGTH), and even that
|
|
would be rare (if all but one 11000 polys were taken). when a new polygon is needed
|
|
get_open_poly is called, it will search through the quick look array untill it finds
|
|
a segment that has an empty member in it (if any element in the segment represented
|
|
by the quick look array is available then that element of the quicklook array will
|
|
be false) then it will look through the found segment, and only that segment, untill it
|
|
finds the empty poly that _is_ there. a great deal of time was spent ensureing that the
|
|
quicklook array was in sync with the big_ol_decal_poly_array. once a poly is found it is
|
|
marked as used and, if no more polys in the segment are free, that segment is marked (with
|
|
true) as being totaly occupied
|
|
|
|
Debugging Functions
|
|
there are sevral debugging functions, they check the consistency of the lists, they only work
|
|
in debug and they are _REALY >>_SLOW_<<_ wich is why they are all disabled, I don't
|
|
even know if they still all/any work. enable at your own risk.
|
|
|
|
|
|
|
|
DECAL CREATION:
|
|
High Level Decal Creation Interface
|
|
for anyone wanting to add a decal to a ship, it is very simple, you simply fill out a
|
|
decal_point structure and pass it along with what texture(s) you want the decal to use
|
|
and the object (as ship) that you want it to be applyed to to the aptly named decal_create
|
|
(currently subobjects are not suported so just ignore that paraeter for now).keep in mind
|
|
that decals are organised by there primary texture, make sure you always send the same
|
|
bunch of textures along with the primary texture (this is an issue I need to work on).
|
|
|
|
High Level Decal Creation
|
|
the mentioned decal_create takes the decal_point you give it and constructs a decal_cube,
|
|
(see setup_decal_cube for the monotanus code) a rectangular volume defined by 6 planes
|
|
(defined by a point and a normal each). if a backfaced texture is requested a second
|
|
decal will be made, the model of the ship is then aquired and the innards of the BSP
|
|
parseing take care of generateing polygons.
|
|
|
|
Low Level Decal Creation (the BSP parseing)
|
|
Parseing of the BSP is done through a serese of recersive functions, the first in the line
|
|
is decal_create_sub, it is passed a pointer to the BSP data and sends it off to the proper
|
|
sub functions:
|
|
decal_create_defpoints -
|
|
this function parses the defpoints portion of the BSP data, it allocates and set's up
|
|
the decal_point_list and decal__poly via the decal_realc_pointlist function. it then stuffs
|
|
decal_point_list with pointers to all of the vec3d defpoints within the defpoint chunck, at
|
|
the time of documantation it ignores normals.
|
|
decal_create_sortnorm -
|
|
this function takes care of the sortnorm chunck, it actualy ignores the sort norms them selves,
|
|
but it uses the bounding boxes to speed up generation of the decal, as well as improve the
|
|
quality of the final decal. it finds wich sections of the BSP data should be ignored and
|
|
wich ones should be procesed further, those wich should be procesed further are sent back
|
|
through decal_create_sub wich then recersivelty searches through the rest of the sortnorms
|
|
untill it finds a tmappoly chunk.
|
|
decal_create_tmappoly -
|
|
wich brings us the the heart of the decal creation code, decal_create_tmappoly. this function
|
|
works on the actual polygons of the model. there have bee sevral culling methods used to speed
|
|
things up, but they are fairly irrelevent. what this function realy does is it calculates the
|
|
distance of each of the points on the polygon from two of the decal planes, it then takes that
|
|
result and generates UV coords, if all the points are outside of a 0.0 to 1.0 range the poly is
|
|
discarded, additional testing is done on a third plane to see if the polygon is too far along
|
|
the decal's z axis to be used.
|
|
|
|
|
|
DECAL RENDERING AND VERTEX BUFFER MANAGEMENT
|
|
Vertex Buffers
|
|
as mentioned in the decal management section, decals are organised by texture, this is becase
|
|
they are all rendere at the same time via a vertex buffer, and each decal list has a texture
|
|
and vertex buffer assosiated with it. any time a new decal is added to a list it's vertex
|
|
buffer needs to be rebuilt, this is done in a manner similar to that used by the model rendering
|
|
system, a poly list is used and allocated with the proper sized buffers for as many polys as
|
|
it will be sending to the API level VB code, then it is filled with the vertex data of all
|
|
decals. then it's sent off to be made into a vertex buffer and the returned index is stored
|
|
by the decal list controle.
|
|
|
|
Rendering
|
|
after the vertex buffer has been made, the decal lists are gone through one at a time, the
|
|
texture for the list is set, then a call is made to render the vertex buffer.
|
|
|
|
recent additions hav also taken advantage of the ability to rnder part of a VB.
|
|
enableing dynamic rnedering of decals, this is currently being worked on, and
|
|
is not covered in this documentation.
|
|
|
|
*/
|
|
|
|
|
|
#include "object/object.h"
|
|
#include "globalincs/linklist.h"
|
|
#include "decals/decals.h"
|
|
#include "render/3d.h"
|
|
#include "io/timer.h"
|
|
#include "math/fvi.h"
|
|
#include "lighting/lighting.h"
|
|
#include "debugconsole/timerbar.h"
|
|
#include "ship/ship.h"
|
|
|
|
|
|
|
|
int decal_total_decals_made = 0;
|
|
int total_polys_used = 0;
|
|
int highest_poly_index = 0;
|
|
int highest_decal_index = 0;
|
|
|
|
bool quick_find_array[QUICKFIND_SUBDIVISION] = {false};
|
|
//this subdivides the lower array into smaller chunks so that an empy slot can be found quicker
|
|
//if any of these are false then that means that there is atleast one empty slot within the range it represents
|
|
decal_poly big_ol_decal_poly_array[MAX_GLOBAL_DECAL_POLYS];
|
|
|
|
decal_item big_ol_decal_array[MAX_GLOBAL_DECALS];
|
|
|
|
/****BSP Defpoint Buffer Start****/
|
|
vec3d **decal_point_list = NULL;
|
|
int *decal__poly = NULL;
|
|
//those two are used deep within the bowels of the BSP parseing code
|
|
|
|
int decal_points_allocated = 0;
|
|
|
|
//model data is held in dynamic memory, it's only reallocated when
|
|
|
|
//the current buffers are too small, this free's the buffers atexit (see end of init_decals)
|
|
void free_decal_stuff(){
|
|
if(decal_points_allocated){
|
|
//if either one of these arn't NULL than someone allocated something to them
|
|
if(decal_point_list)vm_free(decal_point_list);
|
|
if(decal__poly)vm_free(decal__poly);
|
|
}
|
|
}
|
|
|
|
//will reallocate the lists (_without_ saveing what was in them!)
|
|
//if the passed size is bigger than what is currently allocated
|
|
void decal_realc_pointlist(int n){
|
|
if(decal_points_allocated < n){
|
|
//if they've been allocated already free what they have
|
|
if(decal_point_list)vm_free(decal_point_list);
|
|
if(decal__poly)vm_free(decal__poly);
|
|
//then reallocate with the new point count
|
|
decal_point_list = (vec3d**) vm_malloc(sizeof(vec3d *)*n);
|
|
decal__poly = (int*) vm_malloc(sizeof(int)*n);
|
|
decal_points_allocated = n;
|
|
}
|
|
}
|
|
/****BSP Defpoint Buffer End****/
|
|
|
|
/****init stuff****/
|
|
bool decals_once_init = false;
|
|
void init_decals(){
|
|
int i;
|
|
|
|
//quick find is set to be false everyware because there are no decals, and thus no polys
|
|
for(i = 0; i<QUICKFIND_SUBDIVISION; i++)
|
|
quick_find_array[i] = false;
|
|
|
|
//every poly has a pointer to it's parent (used for error checking)
|
|
//and the next poly in the list (and for debugging perposes it's index)
|
|
//as these decals are all free at the begining these pointers are all NULL
|
|
for( i = 0; i<MAX_GLOBAL_DECAL_POLYS; i++){
|
|
big_ol_decal_poly_array[i].parent = NULL;
|
|
big_ol_decal_poly_array[i].next = NULL;
|
|
//#ifndef NDEBUG
|
|
big_ol_decal_poly_array[i].idx = i;
|
|
//#endif
|
|
}
|
|
|
|
//no decals are used, they don't have any polys,
|
|
//there are none next in the list of decals (becase they are free and not in a list)
|
|
//and they have no poly list
|
|
for( i = 0; i<MAX_GLOBAL_DECALS; i++){
|
|
big_ol_decal_array[i].used = false;
|
|
big_ol_decal_array[i].dec.dec.n_poly = 0;
|
|
big_ol_decal_array[i].dec.next = NULL;
|
|
// big_ol_decal_array[i].dec.next_burn = NULL;
|
|
big_ol_decal_array[i].dec.dec.poly = NULL;
|
|
}
|
|
|
|
if(!decals_once_init){
|
|
//see I told you it was hear
|
|
atexit(free_decal_stuff);
|
|
decals_once_init = true;
|
|
}
|
|
}
|
|
|
|
/****begin ugly debugging functions****/
|
|
//I'm not documanting this becase there all disabled, and overly redundent and stupid
|
|
//alright, some debugging functions
|
|
|
|
//#define DECAL_DEBUGGING
|
|
//looks at all the decals in all the ships and makes sure there ok
|
|
void check_ship_decals(){
|
|
#ifndef DECAL_DEBUGGING
|
|
return;
|
|
#else
|
|
for(int i = 0; i<MAX_SHIPS; i++){
|
|
ship *shipp = &Ships[i];
|
|
|
|
for(int j = 0; j<shipp->ship_decal_system.n_decal_textures; j++){
|
|
decal_list_controle* list= shipp->ship_decal_system.decals;
|
|
|
|
if(!list->n_decals)Assert(!list->d_list); //if there are no decals there should be no list
|
|
if(!list->d_list)Assert(!list->n_decals); //if there are no list there should be no decals
|
|
if(list->n_decals)Assert(list->d_list); //if there are decals there should be a list
|
|
if(list->d_list)Assert(list->n_decals); //if there are list there should be some decals
|
|
|
|
decal_list *decl = list->d_list;
|
|
for(int d = 0; d<list->n_decals; d++){
|
|
decal *dec = &decl->dec;
|
|
dec->n_poly;
|
|
|
|
decal_poly* p = dec->poly;
|
|
if(!dec->n_poly)Assert(dec->poly == NULL); //if there are no polys there should be no polys
|
|
int n = 0;
|
|
while(p != NULL){
|
|
n++;
|
|
Assert(n <= dec->n_poly);
|
|
p = p->next;
|
|
}
|
|
Assert(n == dec->n_poly);
|
|
|
|
decl = decl->next;
|
|
}
|
|
}
|
|
}
|
|
#endif // DECAL_DEBUGGING
|
|
}
|
|
|
|
// make sure this poly is withing the list, and while you'r at it, make sure there are the corect number of polys
|
|
bool check_decal(decal* dec, decal_poly* poly){
|
|
#ifndef DECAL_DEBUGGING
|
|
return true;
|
|
#else
|
|
#ifndef NDEBUG
|
|
if(dec == NULL)return (poly->next==NULL)?true:false;
|
|
decal_poly* p = dec->poly;
|
|
if(p == NULL)return (dec == NULL)?true:false;
|
|
int n = 0;
|
|
while(p != NULL){
|
|
n++;
|
|
Assert(n <= dec->n_poly);
|
|
if(p == poly)return true;
|
|
p = p->next;
|
|
}
|
|
Assert(n == dec->n_poly);
|
|
return false;
|
|
#endif
|
|
return true;
|
|
#endif // DECAL_DEBUGGING
|
|
}
|
|
|
|
bool decal_is_in_proper_list(decal* dec){
|
|
#ifndef NDEBUG
|
|
if(dec == NULL){
|
|
Error(LOCATION, "decal is null!");
|
|
return false;
|
|
}
|
|
decal_list_controle *list = dec->parent;
|
|
if(list == NULL){
|
|
if(dec->n_poly || dec->poly)Error(LOCATION, "decal list is null");
|
|
return false;
|
|
}
|
|
decal_list *decl = list->d_list;
|
|
if(decl == NULL){
|
|
Error(LOCATION, "list controle has no list");
|
|
return false;
|
|
}
|
|
while(decl != NULL){
|
|
if(dec == &decl->dec)return true;
|
|
decl = decl->next;
|
|
}
|
|
return false;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
//looks at all decals and makes sure there all ok
|
|
void check_list_decals(){
|
|
#ifndef DECAL_DEBUGGING
|
|
return;
|
|
#else
|
|
#ifndef NDEBUG
|
|
for(int i = 0; i<MAX_GLOBAL_DECALS; i++){
|
|
decal_item* d = &big_ol_decal_array[i];
|
|
decal_list* dec = &d->dec;
|
|
decal_is_in_proper_list(&dec->dec);
|
|
if(d->used){
|
|
decal_poly* p = dec->dec.poly;
|
|
// if(!dec->dec.n_poly)Assert(dec->dec.poly == NULL); //if there are no polys there should be no polys
|
|
int n = 0;
|
|
while(p != NULL){
|
|
n++;
|
|
|
|
Assert(n <= dec->dec.n_poly);
|
|
p = p->next;
|
|
}
|
|
Assert(n == dec->dec.n_poly);
|
|
Assert(p == NULL);
|
|
}
|
|
}
|
|
#endif
|
|
#endif // DECAL_DEBUGGING
|
|
}
|
|
|
|
//looks at all pollys, and the quicklook table, makes sure everything is cosuer
|
|
void check_poly_decals(){
|
|
#ifndef DECAL_DEBUGGING
|
|
return;
|
|
#else
|
|
#ifndef NDEBUG
|
|
int i;
|
|
|
|
for(int q = 0; q<QUICKFIND_SUBDIVISION; q++){
|
|
//look in each quicklook segment
|
|
for(i = q*QUICKFIND_SEGMENT_LENGTH; i<(q+1)*QUICKFIND_SEGMENT_LENGTH; i++){
|
|
//in each poly within the segment make sure everything is as it should be
|
|
if(!quick_find_array[q]){
|
|
//make sure there is at least one free
|
|
if(big_ol_decal_poly_array[i].parent == NULL)break;
|
|
}else{
|
|
//make sure there all full in here
|
|
Assert(big_ol_decal_poly_array[i].parent != NULL);
|
|
//this quicklook segment should be totaly occupied
|
|
}
|
|
}
|
|
if(!quick_find_array[q])Assert(i != (q+1)*QUICKFIND_SEGMENT_LENGTH);
|
|
//the quicklook should have an empy but it doesn't!!!
|
|
}
|
|
|
|
for(i = 0; i<MAX_GLOBAL_DECAL_POLYS; i++){
|
|
Assert(check_decal(big_ol_decal_poly_array[i].parent, &big_ol_decal_poly_array[i]));
|
|
}
|
|
#endif
|
|
#endif // DECAL_DEBUGGING
|
|
}
|
|
/****end ugly debugging functions****/
|
|
//I feel dirty...
|
|
|
|
|
|
/*****************************/
|
|
/*BEGING DECAL POLY MANAGEMENT*/
|
|
/*****************************/
|
|
|
|
//finds an available polygon (triangle)
|
|
decal_poly* get_open_poly(){
|
|
|
|
int i, j;
|
|
|
|
check_list_decals();
|
|
SAFEPOINT("entering get_open_poly");
|
|
check_poly_decals();
|
|
check_ship_decals();
|
|
|
|
//look through the quicklook array
|
|
for(i = 0; i<QUICKFIND_SUBDIVISION; i++)
|
|
if(!quick_find_array[i]) break;
|
|
//untill you find a segment that had an empty slot (false)
|
|
|
|
int s = i; //s = segment, it's were you are in the quicklook
|
|
int end = ((i+1)*QUICKFIND_SEGMENT_LENGTH); //start of the next segment
|
|
//were we are going to stop looking in the big_ol_decal_poly_array
|
|
|
|
//i*QUICKFIND_SEGMENT_LENGTH == the start of segment i
|
|
//so go from the start of the segment we know is empty to the end of it
|
|
for(i = i*QUICKFIND_SEGMENT_LENGTH; i<end; i++){
|
|
check_poly_decals();
|
|
|
|
//within this segment look at each member and see if it is assigned to anyone
|
|
if(big_ol_decal_poly_array[i].parent == NULL){
|
|
//if it isn't then that's the one we want
|
|
if(i == end)quick_find_array[s]=true;
|
|
//if this is the last element then this segment is now full
|
|
Assert(big_ol_decal_poly_array[i].next == NULL);
|
|
big_ol_decal_poly_array[i].next = NULL;
|
|
//just to make sure
|
|
|
|
for(j = i+1; j<end; j++){
|
|
//see if there are any empties left in this segment
|
|
//if there aren't mark this segment as full
|
|
if(big_ol_decal_poly_array[j].parent == NULL)break;
|
|
}
|
|
if(j == end)quick_find_array[s]=true;
|
|
//if it couldn't find any empties, then this segment is full
|
|
else quick_find_array[s]=false;
|
|
//otherwise it's still got some space left in it
|
|
|
|
SAFEPOINT("leaveing get_open_poly");
|
|
//and were done :D
|
|
if(i > highest_poly_index){
|
|
highest_poly_index = i;
|
|
mprintf(("highest poly used: %d; highest decal used: %d", highest_poly_index, highest_decal_index));
|
|
}
|
|
return &big_ol_decal_poly_array[i];
|
|
}
|
|
}
|
|
//bad bad bad bad bad...
|
|
//couldn't find an empty within the segment that it was told was empty
|
|
//bad BAD _BAD_ !!!!!11!!!1!
|
|
//_realy freaking bad_
|
|
|
|
check_ship_decals();
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
Warning(LOCATION, "get_open_poly failed\n");
|
|
//it's so bad were gona just stop everything and tell you about it
|
|
SAFEPOINT("leaveing get_open_poly");
|
|
return NULL;
|
|
}
|
|
|
|
//mark this poly as free also tell the quicklook array that there is something open here
|
|
void free_poly(decal_poly* poly, bool error_check = true){
|
|
if(error_check){
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
}
|
|
SAFEPOINT("entering free_poly");
|
|
Assert(poly != NULL || poly->parent != NULL);
|
|
|
|
int idx = int(poly - big_ol_decal_poly_array);//tricky :D,
|
|
//get's the index by pointer subtraction, was suprized this worked
|
|
|
|
int i = idx/QUICKFIND_SEGMENT_LENGTH;
|
|
//get the quicklook index
|
|
quick_find_array[i] = false;
|
|
//set it to false
|
|
poly->parent = NULL;
|
|
poly->next = NULL;
|
|
//clear out andything that it has in relation to it's old master
|
|
#ifndef NDEBUG
|
|
//this is some stuff to make sure that I got the right index
|
|
Assert(i*QUICKFIND_SEGMENT_LENGTH <= poly->idx);
|
|
Assert((i+1)*QUICKFIND_SEGMENT_LENGTH > poly->idx);
|
|
Assert(idx == poly->idx);
|
|
#endif
|
|
SAFEPOINT("leaveing free_poly");
|
|
//done
|
|
if(error_check){
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
}
|
|
}
|
|
|
|
decal_poly* decal::add_poly(){
|
|
SAFEPOINT("entering decal::add_poly");
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
|
|
//get the last poly on the poly list for this decal
|
|
decal_poly* ppoly = get_last_poly();
|
|
|
|
//if you couldn't get any, that means there were none to get
|
|
//this is the first poly in the list
|
|
if(ppoly == NULL){
|
|
Assert(n_poly == 0);// make sure this decal know's that it's empty
|
|
//allocate a new poly
|
|
poly = get_open_poly();
|
|
//set it's parent to this
|
|
poly->parent = this;
|
|
//put it into this decal's poly list as the first
|
|
ppoly = poly; //we can use this without getting a read/write to NULL error :)
|
|
}else{
|
|
//get a new poly and place it at the end of the list
|
|
ppoly->next = get_open_poly();//add one to it
|
|
//move the end poly back one so we can use the new poly we just got a little easier
|
|
ppoly = ppoly->next;
|
|
}
|
|
if(ppoly == NULL){
|
|
//ok, something when cataclismicly wrong :(
|
|
//get_open_poly probly failed
|
|
SAFEPOINT("leaveing decal::add_poly NULL");
|
|
return NULL;
|
|
}
|
|
//ppoly is the end of the list, there should be no other polys after it
|
|
ppoly->next = NULL;
|
|
//well we've got one more poly than we did when we came in here
|
|
n_poly++;
|
|
//this is important to make sure it has the parent set corectly
|
|
ppoly->parent = this;
|
|
#ifndef NDEBUG
|
|
//hmm... don't ask...
|
|
Assert(ppoly->parent == this);
|
|
#endif
|
|
check_poly_decals();
|
|
check_list_decals();
|
|
SAFEPOINT("leaveing decal::add_poly Vailid");
|
|
return ppoly; //and return the new poly we got
|
|
}
|
|
|
|
void decal::remove_last_poly(){
|
|
check_list_decals();
|
|
SAFEPOINT("entering decal::remove_last_poly");
|
|
check_poly_decals();
|
|
|
|
decal_poly* p = poly; //get the start of the list
|
|
decal_poly *last = NULL;
|
|
if(p==NULL){ // if it's NULL than there are no polys in this list, return NULL
|
|
Assert(!n_poly);
|
|
SAFEPOINT("leaveing decal::remove_last_poly NULL");
|
|
return ; //the first time
|
|
}
|
|
last = p;
|
|
while(p->next != NULL){// untill we find one that doesn't have anymore afer it
|
|
Assert(p->parent == this);//check for consistency
|
|
last = p;
|
|
p = p->next;//find the end of the list, move on down the line
|
|
}
|
|
last->next = NULL; //this is now the end of the list
|
|
n_poly--;
|
|
free_poly(p, false); //I'm afraid you've outlived your usefulness as a polygon in this decal
|
|
if(!n_poly)poly = NULL;
|
|
//if there are no polys in the list after were done, kill off the list
|
|
Assert(p->parent == NULL);
|
|
check_poly_decals();
|
|
check_list_decals();
|
|
SAFEPOINT("leaveing decal::remove_last_poly valid");
|
|
}
|
|
|
|
//retuns the last polly of the decal
|
|
decal_poly *decal::get_last_poly(){
|
|
SAFEPOINT("entering decal::get_last_poly");
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
|
|
decal_poly* p = poly; //get the start of the list
|
|
if(p==NULL){ // if it's NULL than there are no polys in this list, return NULL
|
|
SAFEPOINT("leaveing decal::get_last_poly NULL");
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
return p; //the first time
|
|
}
|
|
while(p->next != NULL){// untill we find one that doesn't have anymore afer it
|
|
Assert(p->parent == this);//check for consistency
|
|
p = p->next;//find the end of the list, move on down the line
|
|
}
|
|
//we got it
|
|
Assert(p->parent == this);
|
|
check_poly_decals();
|
|
SAFEPOINT("leaveing decal::get_last_poly valid");
|
|
//it's p
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
return p;
|
|
}
|
|
|
|
//frees all polys from a decal
|
|
void free_all_polys(decal* dec){
|
|
if(!dec)return;
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
decal_poly* poly = dec->poly;
|
|
while(poly){
|
|
decal_poly* next_poly = poly->next;
|
|
dec->n_poly--;
|
|
free_poly(poly, false);
|
|
poly = next_poly;
|
|
}
|
|
Assert(dec->n_poly == 0);
|
|
//this decal is now empty make sure it is marked as such
|
|
dec->poly = NULL;
|
|
dec->n_poly = 0;
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
}
|
|
|
|
/***************************/
|
|
/*END DECAL POLY MANAGEMENT*/
|
|
/***************************/
|
|
|
|
|
|
|
|
|
|
/************************/
|
|
/*BEGIN DECAL MANAGEMENT*/
|
|
/************************/
|
|
|
|
//finds the first free decal
|
|
//allocates it, be sure to free with free_decal_list
|
|
decal_list* get_open_decal_list(){
|
|
|
|
SAFEPOINT("entering get_open_decal_list");
|
|
check_poly_decals();
|
|
check_list_decals();
|
|
|
|
for(int i = 0; i<MAX_GLOBAL_DECALS; i++){
|
|
if(!big_ol_decal_array[i].used){
|
|
//look untill you find one that isn't used
|
|
big_ol_decal_array[i].used = true;
|
|
//mark it as used
|
|
|
|
check_poly_decals();
|
|
SAFEPOINT("leaveing get_open_decal_list");
|
|
if(i > highest_decal_index){
|
|
highest_decal_index = i;
|
|
mprintf(("highest poly used: %d; highest decal used: %d", highest_poly_index, highest_decal_index));
|
|
}
|
|
|
|
return &big_ol_decal_array[i].dec;
|
|
//and return it
|
|
}
|
|
}
|
|
|
|
Warning(LOCATION, "get_open_decal_list failed\n");
|
|
SAFEPOINT("leaveing get_open_decal_list");
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
return NULL;
|
|
}
|
|
|
|
//makes the low level decal management see this as free
|
|
void free_decal_list(decal_list* dec){
|
|
SAFEPOINT("entering free_decal_list");
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
for(int i = 0; i<MAX_GLOBAL_DECALS; i++){
|
|
//find the decal in the array
|
|
if(&big_ol_decal_array[i].dec == dec){
|
|
//free it's pollys
|
|
free_all_polys(&dec->dec);;
|
|
//then mark it as not being used
|
|
#ifndef NDEBUG
|
|
dec->dec.parent = NULL;
|
|
#endif
|
|
big_ol_decal_array[i].used = false;
|
|
}
|
|
}
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
SAFEPOINT("leaveing free_decal_list");
|
|
}
|
|
|
|
//add's a new decal to the list
|
|
decal_list *decal_list_controle::add_new(){
|
|
SAFEPOINT("entering decal_list_controle::add_new");
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
check_ship_decals();
|
|
//if the end decal is empty just use that
|
|
if(n_decals && !end->dec.n_poly){
|
|
// n_decals++;
|
|
return end;
|
|
}
|
|
|
|
//if d_list is empty, then this is the first decal,
|
|
//put the new decal at the start of the list (d_list)
|
|
//otherwise use the decal after the last one in the list
|
|
decal_list** dl = (d_list == NULL)?&d_list:&end->next;
|
|
*dl = get_open_decal_list();
|
|
if(dl == NULL){
|
|
//if we couldn't get an open decal quit
|
|
return NULL;
|
|
}
|
|
|
|
//if dl == d_list then this is the first decal
|
|
//it's also the last decal, mark it acordingly
|
|
if(&d_list == dl){
|
|
end = d_list;
|
|
}else{
|
|
//otherwise move the end down one
|
|
end = end->next;
|
|
}
|
|
//now that end has been set to the corect position, there should be no more decals after it
|
|
//next should already be NULL due to the freeing function, but just to make sure
|
|
end->next = NULL;
|
|
|
|
//make sure this decal is empty, though it should be anyway
|
|
decal_poly *poly = (*dl)->dec.poly;
|
|
for(int i = 0; i<(*dl)->dec.n_poly; i++){
|
|
//maybe an error mesage should go in here, becase this realy should never be getting called
|
|
decal_poly *next = poly->next;
|
|
free_poly(poly);
|
|
poly = next;
|
|
}
|
|
Assert(poly == NULL);
|
|
|
|
//another make-absolutely-sure-the-data-leaveing-this-function-is-corect thingy
|
|
(*dl)->dec.n_poly = 0;
|
|
(*dl)->dec.poly = NULL;
|
|
|
|
//we now have one more decal in this list than we did before
|
|
n_decals++;
|
|
|
|
modifyed = true; //mark this decal list as haveing been modifyed
|
|
check_ship_decals();
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
SAFEPOINT("leaveing decal_list_controle::add_new");
|
|
#ifndef NDEBUG
|
|
(*dl)->dec.parent = this;
|
|
#endif
|
|
check_list_decals();
|
|
|
|
check_ship_decals();
|
|
|
|
return *dl;
|
|
};
|
|
|
|
//removes the first item from the list and puts the emptied decal on the end
|
|
void decal_list_controle::trim(){
|
|
SAFEPOINT("entering decal_list_controle::trim");
|
|
|
|
check_ship_decals();
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
//get the poly list
|
|
//hack fix
|
|
if(!d_list)Error(LOCATION, "decal list is null in trim");//return;
|
|
decal_poly *poly = d_list->dec.poly;
|
|
if(poly)free_all_polys(&d_list->dec);
|
|
/* for(int i = 0; i<d_list->dec.n_poly; i++){
|
|
if(!poly)Error(LOCATION, "poly list is corupt in trim");//break;
|
|
//grab wich poly is to be next
|
|
decal_poly *next = poly->next;
|
|
//then kill the poly
|
|
free_poly(poly);
|
|
//move to the next poly
|
|
poly = next;
|
|
}*/
|
|
else
|
|
if(d_list->dec.n_poly)Error(LOCATION, "poly list is missing in trim");
|
|
#ifndef NDEBUG
|
|
d_list->dec.parent = this;//heh, becase it's still part of this decal list,, duh...
|
|
#endif
|
|
SAFEPOINT("decal_list_controle::trim; polys cleared");
|
|
//the poly being pointed to here is no longer valid,
|
|
//also marking this as null means that there are no polys in it
|
|
if(!d_list)Error(LOCATION, "decal list is null in trim 1");//return;
|
|
d_list->dec.poly = NULL;
|
|
//poly should have made it to the end of the list, make sure that it did
|
|
if(!d_list)Error(LOCATION, "decal list is null in trim 2");//return;
|
|
// Assert(poly == NULL);
|
|
d_list->dec.n_poly = 0;
|
|
if(!d_list)Error(LOCATION, "decal list is null in trim 3");//return;
|
|
//the end is the first
|
|
end->next = d_list;
|
|
if(!d_list)Error(LOCATION, "decal list is null in trim 4");//return;
|
|
//the end is pushed back
|
|
end = end->next;
|
|
if(!d_list)Error(LOCATION, "decal list is null in trim 5");//return;
|
|
//the first is the second
|
|
d_list = d_list->next;
|
|
//the end is NULLed off
|
|
if(!d_list)Error(LOCATION, "decal list is null in trim 6");//return;
|
|
end->next = NULL;
|
|
if(!d_list)Error(LOCATION, "decal list is null in trim 7");//return;
|
|
check_poly_decals();
|
|
modifyed = true; //mark this decal list as haveing been modifyed
|
|
if(!d_list)Error(LOCATION, "decal list is null at the end of trim");//return;
|
|
SAFEPOINT("leaveing decal_list_controle::trim");
|
|
|
|
check_ship_decals();
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
//no decals were killed in the recycleing of this decal
|
|
};
|
|
|
|
void decal_list_controle::clear(){
|
|
SAFEPOINT("entering deecal_list_controle::clear");
|
|
check_ship_decals();
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
|
|
decal_list *n = d_list;
|
|
decal_list *c = d_list;
|
|
decal_list *list = d_list;
|
|
|
|
while(n != NULL){
|
|
n = list->next;
|
|
free_decal_list(list);
|
|
c = list; //this is to make sure it's getting to the end of the list
|
|
list = n;
|
|
n_decals--;
|
|
}
|
|
Assert(c == end);//see it got to the end, stop worrying
|
|
Assert(!n_decals);
|
|
d_list = NULL;
|
|
|
|
modifyed = true; //mark this decal list as haveing been modifyed, might as well even though it probly won't getting used
|
|
check_poly_decals();
|
|
check_list_decals();
|
|
check_ship_decals();
|
|
|
|
SAFEPOINT("leaveing deecal_list_controle::clear");
|
|
};
|
|
|
|
decal_list_controle::decal_list_controle():n_decals(0),buffer(-1),texture(-1),modifyed(false),d_list(NULL),end(NULL){
|
|
}
|
|
|
|
decal_list_controle::~decal_list_controle(){
|
|
clear();
|
|
};
|
|
|
|
/****high level decal management****/
|
|
|
|
//find a decal list with the texture we want from an array of decal lists
|
|
decal_list_controle *find_list(decal_list_controle* list, int n_textures, int texture){
|
|
for(int i = 0; i < n_textures; i++){
|
|
//if this decal list is useing our text return it
|
|
if(list[i].texture == texture)return &list[i];
|
|
}
|
|
//couldn't find any
|
|
return NULL;
|
|
}
|
|
|
|
decal *decal_find_next(decal_system* system, int texture, int glow_texture = -1, int burn_texture = -1){
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
check_ship_decals();
|
|
SAFEPOINT("entering decal_find_next");
|
|
|
|
//see if you can find a decal list already in exsistence that uses the texture we want
|
|
decal_list_controle* list = find_list( system->decals, system->n_decal_textures, texture);
|
|
if(list == NULL){
|
|
//if it couldn't find the texture, this means we need to
|
|
//reallocate the array and add one
|
|
system->decals = (decal_list_controle*)vm_realloc(system->decals, sizeof(decal_list_controle) * ++system->n_decal_textures);
|
|
|
|
if(!system->decals)Error(LOCATION, "unable to malloc new decal list");
|
|
|
|
list = &system->decals[system->n_decal_textures-1];
|
|
list->buffer = -1;
|
|
list->d_list = NULL;
|
|
list->end = NULL;
|
|
list->texture = texture;
|
|
list->burn_texture = burn_texture;
|
|
list->glow_texture = glow_texture;
|
|
list->n_decals = 0;
|
|
|
|
for(int i = 0; i<system->n_decal_textures -1; i++){
|
|
decal_list *decl = system->decals[i].d_list;
|
|
if(decl == NULL){
|
|
Error(LOCATION, "list controle has no list");
|
|
break;
|
|
}
|
|
while(decl != NULL){
|
|
decl->dec.parent = &system->decals[i];
|
|
decl = decl->next;
|
|
}
|
|
}
|
|
|
|
//set up the innital values for a new list,
|
|
//nulling out the first members setting the textures ect...
|
|
check_ship_decals();
|
|
}
|
|
if(!system->decals)Error(LOCATION, "decal list lost");
|
|
//ok so now we've got the list controle
|
|
//lets get the actual linked list of decals
|
|
decal_list* l = list->d_list;
|
|
bool trimcalled = false;
|
|
if(!system->max_decals)system->max_decals = 10;//this should never happen, but it is and I'm to lazy to fix it properly
|
|
if(list->n_decals >= system->max_decals){
|
|
list->trim();
|
|
trimcalled = true;
|
|
}
|
|
//if we have the max number of decals kill the oldest one.
|
|
//this will no longer allocate any memory, it just keeps recycleling what it has
|
|
|
|
if(list->n_decals == 0){
|
|
l = list->add_new();
|
|
// no decals in this list, so we need to make one
|
|
}else if(list->end->dec.n_poly != 0){
|
|
l = list->add_new();
|
|
//if the last decal already has polys in it get a new one
|
|
}
|
|
if(l == NULL){
|
|
//umm, something went realy wrong, not sure what happens if this happens
|
|
SAFEPOINT("leaveing decal_find_next NULL");
|
|
return NULL;
|
|
}
|
|
// so now we have a good (hopefully empty) decal at the end of our list
|
|
SAFEPOINT("leaveing decal_find_next");
|
|
check_poly_decals();
|
|
check_ship_decals();
|
|
check_list_decals();
|
|
if(!system->decals)Error(LOCATION, "decal list lost");
|
|
|
|
list->modifyed = true;//it should aslways read as modified after this function
|
|
return &list->end->dec;
|
|
//return a pointer to the decal at the end of the list
|
|
}
|
|
|
|
void clear_decals(decal_system *system)
|
|
{
|
|
int i;
|
|
if(!system->n_decal_textures)return;
|
|
for( i = 0; i<system->n_decal_textures; i++)system->decals[i].clear();
|
|
for( i = 0; i<system->n_decal_textures; i++)Assert(!system->decals[i].n_decals);
|
|
system->n_decal_textures = 0;
|
|
vm_free(system->decals);
|
|
system->decals = NULL;
|
|
}
|
|
/**********************/
|
|
/*END DECAL MANAGEMENT*/
|
|
/**********************/
|
|
|
|
|
|
|
|
static vec3d decal_cube_point[8];
|
|
static vec3d decal_cube_plane[6][2];
|
|
static vec3d decal_hit_point;
|
|
static vec3d decal_hit_vect;
|
|
static float decal_hit_radius;
|
|
static float decal_min_hit_radius;
|
|
|
|
static matrix decal_orient;
|
|
//the orientation of the decal
|
|
|
|
static decal * new_decal;
|
|
static decal * new_decal_backface;
|
|
|
|
static int nverts;
|
|
|
|
static float min_rad;
|
|
float max_rad;
|
|
// the minimum radius of the decal anything within this distance _is_ in the decal
|
|
|
|
static int back_faceing; //global boolian type thing telling the low level stuff it it's going to care about back faced polys
|
|
|
|
//early simple decal creation code, I don't even know if it works,
|
|
//saveing it becase I may have a use for this type off effect later
|
|
int decal_create_simple(object *obj, decal_point *point, int texture){//makes a simple non-clipped decal
|
|
mprintf(("a decal is about to be made at %0.2f, %0.2f, %0.2f\n", point->pnt.xyz.x, point->pnt.xyz.y, point->pnt.xyz.z));
|
|
mprintf(("orient fvec at %0.2f, %0.2f, %0.2f\n", point->orient.vec.fvec.xyz.x, point->orient.vec.fvec.xyz.y, point->orient.vec.fvec.xyz.z));
|
|
|
|
if(obj->type != OBJ_SHIP){
|
|
return 0;
|
|
}
|
|
// vertex vert[1][2];
|
|
// vec3d vec[4];
|
|
|
|
vec3d center = point->pnt;
|
|
float rad = point->radius;
|
|
if(rad <=0) rad = 10;
|
|
mprintf(("radius %f\n",rad));
|
|
vec3d plain_point[4];
|
|
// mprintf(("orient uvec x %0.2f %0.2f %0.2f\n", point->orient.vec.uvec.xyz.x, point->orient.vec.uvec.xyz.y, point->orient.vec.uvec.xyz.z));
|
|
// mprintf(("orient rvec x %0.2f %0.2f %0.2f\n", point->orient.vec.rvec.xyz.x, point->orient.vec.rvec.xyz.y, point->orient.vec.rvec.xyz.z));
|
|
// mprintf(("orient fvec x %0.2f %0.2f %0.2f\n", point->orient.vec.fvec.xyz.x, point->orient.vec.fvec.xyz.y, point->orient.vec.fvec.xyz.z));
|
|
plain_point[0] = point->orient.vec.uvec;
|
|
plain_point[1] = plain_point[0];
|
|
vm_vec_negate(&plain_point[1]);
|
|
plain_point[2] = point->orient.vec.rvec;
|
|
plain_point[3] = plain_point[2];
|
|
vm_vec_negate(&plain_point[3]);
|
|
|
|
mprintf(("\n"));
|
|
ship *shipp = &Ships[obj->instance];
|
|
|
|
decal *dec = decal_find_next(&shipp->ship_decal_system, texture, -1, -1);
|
|
check_ship_decals();
|
|
if(!dec)return 0;
|
|
|
|
vertex vert[4];
|
|
vec3d _vert[4];
|
|
|
|
for(int i = 0; i<4; i++){
|
|
vm_vec_scale_add( &_vert[i], ¢er, &plain_point[i], rad );
|
|
vm_vec2vert(&_vert[i], &vert[i]);
|
|
}
|
|
|
|
|
|
decal_poly *poly = dec->add_poly();;
|
|
|
|
poly->point[0] = vert[0];
|
|
poly->point[1] = vert[1];
|
|
poly->point[2] = vert[2];
|
|
|
|
poly->point[0].u = 0; poly->point[0].v = 0;
|
|
poly->point[1].u = 0; poly->point[1].v = 1;
|
|
poly->point[2].u = 1; poly->point[2].v = 1;
|
|
|
|
poly = dec->add_poly();
|
|
|
|
poly->point[0] = vert[0];
|
|
poly->point[1] = vert[3];
|
|
poly->point[2] = vert[2];
|
|
|
|
poly->point[0].u = 0; poly->point[0].v = 0;
|
|
poly->point[1].u = 1; poly->point[1].v = 0;
|
|
poly->point[2].u = 1; poly->point[2].v = 1;
|
|
|
|
// dec->texture = texture;
|
|
dec->n_poly = 2;
|
|
|
|
shipp->ship_decal_system.decals_modified = true;
|
|
|
|
mprintf(("a decal should have been made at %0.2f %0.2f %0.2f\n", point->pnt.xyz.x, point->pnt.xyz.y, point->pnt.xyz.z));
|
|
//Int3();
|
|
|
|
return 1;
|
|
}
|
|
|
|
//BSP parseing macros
|
|
#define duw(p) (*((uint *) (p)))
|
|
#define dw(p) (*((int *) (p)))
|
|
#define dwp(p) ((int *) (p))
|
|
#define dvp(p) ((vec3d *) (p))
|
|
#define dfl(p) (*((float *) (p)))
|
|
|
|
|
|
//creates a decal, returns decal index on succes, -1 on failure
|
|
void setup_decal_cube(matrix m, vec3d cube_point[8]){
|
|
|
|
//setting up the decal cube
|
|
vec3d test_vec, temp1, temp2;
|
|
for(int i = 0; i<8; i++)decal_cube_point[i] = cube_point[i];
|
|
|
|
decal_orient = m;
|
|
|
|
decal_cube_plane[0][0] = cube_point[5];
|
|
|
|
temp1 = decal_orient.vec.uvec;
|
|
temp2 = decal_orient.vec.rvec;
|
|
|
|
vm_vec_avg(&test_vec, &temp1, &temp2);
|
|
vm_vec_normalize(&test_vec);
|
|
|
|
decal_cube_plane[0][1] = test_vec;
|
|
|
|
// mprintf(("plane 0 position is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[0][0].xyz.x, decal_cube_plane[0][0].xyz.y, decal_cube_plane[0][0].xyz.z));
|
|
// mprintf(("plane 0 normal is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[0][1].xyz.x, decal_cube_plane[0][1].xyz.y, decal_cube_plane[0][1].xyz.z));
|
|
|
|
|
|
|
|
decal_cube_plane[1][0] = cube_point[0];
|
|
|
|
vm_vec_negate(&test_vec);
|
|
|
|
decal_cube_plane[1][1] = test_vec;
|
|
// mprintf(("plane 1 position is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[1][0].xyz.x, decal_cube_plane[1][0].xyz.y, decal_cube_plane[1][0].xyz.z));
|
|
// mprintf(("plane 1 normal is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[1][1].xyz.x, decal_cube_plane[1][1].xyz.y, decal_cube_plane[1][1].xyz.z));
|
|
|
|
|
|
|
|
decal_cube_plane[2][0] = cube_point[5];
|
|
|
|
vm_vec_negate(&temp2);
|
|
vm_vec_avg(&test_vec, &temp1, &temp2);
|
|
vm_vec_normalize(&test_vec);
|
|
|
|
decal_cube_plane[2][1] = test_vec;
|
|
|
|
// mprintf(("plane 2 position is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[2][0].xyz.x, decal_cube_plane[2][0].xyz.y, decal_cube_plane[2][0].xyz.z));
|
|
// mprintf(("plane 2 normal is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[2][1].xyz.x, decal_cube_plane[2][1].xyz.y, decal_cube_plane[2][1].xyz.z));
|
|
|
|
|
|
|
|
decal_cube_plane[3][0] = cube_point[0];
|
|
|
|
vm_vec_negate(&test_vec);
|
|
|
|
decal_cube_plane[3][1] = test_vec;
|
|
|
|
// mprintf(("plane 3 position is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[3][0].xyz.x, decal_cube_plane[3][0].xyz.y, decal_cube_plane[3][0].xyz.z));
|
|
// mprintf(("plane 3 normal is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[3][1].xyz.x, decal_cube_plane[3][1].xyz.y, decal_cube_plane[3][1].xyz.z));
|
|
|
|
|
|
|
|
test_vec = decal_orient.vec.fvec;
|
|
|
|
decal_cube_plane[4][0] = cube_point[0];
|
|
|
|
decal_cube_plane[4][1] = test_vec;
|
|
|
|
// mprintf(("plane 4 position is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[4][0].xyz.x, decal_cube_plane[4][0].xyz.y, decal_cube_plane[4][0].xyz.z));
|
|
// mprintf(("plane 4 normal is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[4][1].xyz.x, decal_cube_plane[4][1].xyz.y, decal_cube_plane[4][1].xyz.z));
|
|
|
|
|
|
|
|
vm_vec_negate(&test_vec);
|
|
decal_cube_plane[5][0] = cube_point[5];
|
|
|
|
decal_cube_plane[5][1] = test_vec;
|
|
|
|
// mprintf(("plane 5 position is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[5][0].xyz.x, decal_cube_plane[5][0].xyz.y, decal_cube_plane[5][0].xyz.z));
|
|
// mprintf(("plane 5 normal is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[5][1].xyz.x, decal_cube_plane[5][1].xyz.y, decal_cube_plane[5][1].xyz.z));
|
|
//setting up the decal cube
|
|
|
|
mprintf(("cube set up\n"));
|
|
}
|
|
|
|
/**************/
|
|
/*DECAL CREATE*/
|
|
/**************/
|
|
|
|
decal_poly *LAST_POLY;
|
|
int decal_create(object * obj, decal_point *point, int subobject, int texture, int backfaced_texture, int glow_texture, int burn_texture, int burn_time)
|
|
{
|
|
if(!Cmdline_decals)return -1;
|
|
// return -1;
|
|
|
|
SAFEPOINT("entering create_decal");
|
|
mprintf(("a decal is about to be made at %0.2f, %0.2f, %0.2f\n", point->pnt.xyz.x, point->pnt.xyz.y, point->pnt.xyz.z));
|
|
|
|
if(obj->type != OBJ_SHIP){
|
|
return -1;
|
|
}
|
|
if(texture < 0)return -1;
|
|
if(point->radius <= 0)return -1;
|
|
//TIMERBAR_PUSH(TIMERBAR_GREY);
|
|
|
|
vec3d center = point->pnt;
|
|
float rad = point->radius;
|
|
if(rad <=0) rad = 1;
|
|
mprintf(("radius %f\n",rad));
|
|
vec3d plain_point[4];
|
|
vec3d cube_point[8];
|
|
//define the decals dimentions
|
|
plain_point[0] = point->orient.vec.uvec;
|
|
plain_point[1] = plain_point[0];
|
|
vm_vec_negate(&plain_point[1]);
|
|
plain_point[2] = point->orient.vec.rvec;
|
|
plain_point[3] = plain_point[2];
|
|
vm_vec_negate(&plain_point[3]);
|
|
|
|
vec3d topcenter;
|
|
vec3d bvec = point->orient.vec.fvec;
|
|
vm_vec_negate(&bvec);
|
|
vm_vec_scale_add(&topcenter, ¢er, &bvec, rad);
|
|
|
|
for(int i = 0; i < 4; i++){
|
|
vm_vec_scale_add( &cube_point[i], &topcenter, &plain_point[i], rad );
|
|
vm_vec_scale_add( &cube_point[i+4], &cube_point[i], &point->orient.vec.fvec, rad*2);
|
|
}
|
|
|
|
max_rad = vm_vec_dist_quick(¢er, &cube_point[0]); //the cube points are all equidistant, right?
|
|
min_rad = fl_sqrt((rad * rad)/2); //the cube points are all equidistant, right?
|
|
mprintf(("decal defined\n"));
|
|
|
|
//define the decals dimentions
|
|
|
|
//set up the decal model
|
|
ship *shipp = &Ships[obj->instance];
|
|
// decal *sdec = shipp->decals;
|
|
|
|
polymodel *pm = model_get(shipp->modelnum);
|
|
bool hit_main_hull = (pm->detail[0] == subobject);
|
|
bsp_info * sm;
|
|
sm = &pm->submodel[subobject];
|
|
|
|
model_subsystem* psub = NULL;
|
|
//subsys_list
|
|
ship_subsys *sys = GET_FIRST(&shipp->subsys_list);;
|
|
while(sys != END_OF_LIST(&shipp->subsys_list)){
|
|
if(sys->system_info->subobj_num == subobject){
|
|
psub = sys->system_info;
|
|
break;
|
|
}
|
|
sys = GET_NEXT(sys);
|
|
}
|
|
|
|
if(!hit_main_hull && !psub)return -1;
|
|
|
|
decal_system* system = (hit_main_hull)?&shipp->ship_decal_system:&psub->model_decal_system;
|
|
// decal_model dmod = pm->submodel[subobject].dec_model;// sm->dec_model;
|
|
// decal_model tdec; //temporary decal model for holding the culled down part of the decal
|
|
|
|
setup_decal_cube(point->orient, cube_point);
|
|
|
|
decal_hit_point = point->pnt;
|
|
decal_hit_radius = max_rad;
|
|
|
|
// decal_min_hit_radius = min_rad;
|
|
decal_min_hit_radius = rad;
|
|
decal_hit_vect = point->orient.vec.fvec;
|
|
nverts = 0;
|
|
|
|
//go and find decals for each submodel
|
|
// for(int z = 0; z<pm->n_models;z++){
|
|
|
|
if(backfaced_texture != -1)
|
|
new_decal_backface = decal_find_next(system, backfaced_texture,-1,-1);
|
|
else
|
|
new_decal_backface = NULL;
|
|
|
|
//check_poly_decals();
|
|
decal *sdec = decal_find_next(system, texture, glow_texture, burn_texture);
|
|
//check_poly_decals();
|
|
Assert(sdec != NULL);
|
|
// mprintf(("decal is number %d\n", dinx));
|
|
|
|
// sdec->is_valid = 0;
|
|
|
|
new_decal = sdec;
|
|
|
|
if(backfaced_texture != -1){
|
|
back_faceing = 1;
|
|
}else{
|
|
back_faceing = 0;
|
|
}
|
|
//no decal should have any polys before it's been created
|
|
Assert(new_decal->n_poly == 0);
|
|
if(backfaced_texture != -1)
|
|
Assert(new_decal_backface->n_poly == 0);
|
|
SAFEPOINT("");
|
|
LAST_POLY = new_decal->add_poly();
|
|
SAFEPOINT("");
|
|
decal_create_sub((ubyte *)pm->submodel[subobject].bsp_data);
|
|
new_decal->remove_last_poly();
|
|
//there's always one too many polygons made, becase one is always needed to be worked with
|
|
|
|
mprintf(("deacal defined\n"));
|
|
if(new_decal->n_poly){
|
|
new_decal->timestamp = timestamp();
|
|
new_decal->burn_time = burn_time;
|
|
}
|
|
|
|
/* sdec->texture = texture;
|
|
sdec->backfaced_texture = backfaced_texture;
|
|
sdec->is_valid = 1;
|
|
sdec->timestamp = timestamp();
|
|
sdec->state = 1;
|
|
sdec->lifetime = 3000;
|
|
sdec->frames = 1;
|
|
sdec->importance = 0;
|
|
sdec->radius = max_rad;
|
|
sdec->position = point->pnt;
|
|
*/
|
|
|
|
decal_total_decals_made++;
|
|
total_polys_used += sdec[0].n_poly;
|
|
|
|
mprintf(("a decal should have been made with %d polys,\n %d decals have been made with an average of %0.3f polys eachf\n",sdec[0].n_poly, decal_total_decals_made, float(total_polys_used)/float(decal_total_decals_made)));
|
|
|
|
system->decals_modified = true;
|
|
check_poly_decals();
|
|
|
|
//TIMERBAR_POP();
|
|
return 1;
|
|
}
|
|
//decal_model d_model;
|
|
|
|
// Point list
|
|
// +0 int id
|
|
// +4 int size
|
|
// +8 int n_verts
|
|
// +12 int n_norms
|
|
// +16 int offset from start of chunk to vertex data
|
|
// +20 n_verts*char norm_counts
|
|
// +offset vertex data. Each vertex n is a point followed by norm_counts[n] normals.
|
|
void decal_create_defpoints(ubyte * p )
|
|
{
|
|
// mprintf(("entering decal decal_create_defpoints\n"));
|
|
|
|
|
|
int n;
|
|
nverts = dw(p+8);
|
|
int offset = dw(p+16);
|
|
|
|
decal_realc_pointlist(nverts);
|
|
|
|
mprintf(("%d verts\n",nverts));
|
|
ubyte * normcount = p+20;
|
|
vec3d *src = dvp(p+offset);
|
|
|
|
//> Assert( nverts < 1200 );
|
|
|
|
|
|
|
|
for (n=0; n<nverts; n++ ) {
|
|
|
|
Assert(decal_points_allocated >= n);
|
|
|
|
decal_point_list[n] = src;
|
|
// new_decal->vert[n].xyz = src->xyz;
|
|
src += normcount[n]+1;
|
|
// mprintf(("defpoint %d, x %0.2f, y %0.2f, z %0.2f\n",n,d_model.vert[n].xyz.x,d_model.vert[n].xyz.y,d_model.vert[n].xyz.z));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// Sortnorms
|
|
// +0 int id
|
|
// +4 int size
|
|
// +8 vec3d normal
|
|
// +20 vec3d center
|
|
// +32 float radius
|
|
// 36 int front offset
|
|
// 40 int back offset
|
|
// 44 int prelist offset
|
|
// 48 int postlist offset
|
|
// 52 int online offset
|
|
|
|
void decal_create_sortnorm(ubyte * p)
|
|
{
|
|
// mprintf(("entering decal_create_sortnorm\n"));
|
|
int frontlist = dw(p+36);
|
|
int backlist = dw(p+40);
|
|
int prelist = dw(p+44);
|
|
int postlist = dw(p+48);
|
|
int onlist = dw(p+52);
|
|
|
|
vec3d *normal, *point;
|
|
normal = dvp(p+8);
|
|
point = dvp(p+20);
|
|
|
|
vec3d min, max, h;
|
|
min.xyz = dvp(p+56)->xyz;
|
|
max.xyz = dvp(p+68)->xyz;
|
|
min.xyz.x -= decal_hit_radius;
|
|
min.xyz.y -= decal_hit_radius;
|
|
min.xyz.z -= decal_hit_radius;
|
|
max.xyz.x += decal_hit_radius;
|
|
max.xyz.y += decal_hit_radius;
|
|
max.xyz.z += decal_hit_radius;
|
|
|
|
if (!fvi_ray_boundingbox( &min, &max, &decal_hit_point, &decal_hit_vect, &h )) {
|
|
mprintf(("leaveing from sortnorm bbox\n"));
|
|
return;
|
|
}
|
|
|
|
float rad = dfl(p+32);
|
|
float dist = vm_vec_dist( &decal_hit_point, point);
|
|
if(dist <= (rad + max_rad)){
|
|
mprintf(("leaveing from sortnorm rad\n"));
|
|
return;
|
|
}
|
|
|
|
float decal_plane_dist = fvi_point_dist_plane(point, normal, &decal_hit_point);
|
|
bool within = fl_abs(decal_plane_dist) < max_rad;
|
|
|
|
if (prelist) decal_create_sub(p+prelist);
|
|
|
|
if(within)
|
|
if (onlist) decal_create_sub(p+onlist);
|
|
|
|
if(decal_plane_dist > 0.0f){
|
|
if (frontlist) decal_create_sub(p+frontlist);
|
|
if (backlist) decal_create_sub(p+backlist);
|
|
}else{
|
|
if (backlist) decal_create_sub(p+backlist);
|
|
if (frontlist) decal_create_sub(p+frontlist);
|
|
}
|
|
|
|
if(!within)
|
|
if (onlist) decal_create_sub(p+onlist);
|
|
|
|
if (postlist) decal_create_sub(p+postlist);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
typedef struct model_tmap_vert {
|
|
short vertnum;
|
|
short normnum;
|
|
float u,v;
|
|
} model_tmap_vert;
|
|
*/
|
|
|
|
//if all the UVs are out of range this poly can be discarded
|
|
bool check_uv(decal_poly *poly){
|
|
if(poly->point[0].u < 0.0f
|
|
&&
|
|
poly->point[1].u < 0.0f
|
|
&&
|
|
poly->point[2].u < 0.0f
|
|
)
|
|
return false;
|
|
if(poly->point[0].v < 0.0f
|
|
&&
|
|
poly->point[1].v < 0.0f
|
|
&&
|
|
poly->point[2].v < 0.0f
|
|
)
|
|
return false;
|
|
if(poly->point[0].u > 1.0f
|
|
&&
|
|
poly->point[1].u > 1.0f
|
|
&&
|
|
poly->point[2].u > 1.0f
|
|
)
|
|
return false;
|
|
if(poly->point[0].v > 1.0f
|
|
&&
|
|
poly->point[1].v > 1.0f
|
|
&&
|
|
poly->point[2].v > 1.0f
|
|
)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//checks the distance from the capping planes
|
|
bool check_ab(float a[3], float b[3]){
|
|
if(a[0] > 0.0f
|
|
&&
|
|
a[1] > 0.0f
|
|
&&
|
|
a[2] > 0.0f
|
|
)
|
|
return false;
|
|
if(b[0] > 0.0f
|
|
&&
|
|
b[1] > 0.0f
|
|
&&
|
|
b[2] > 0.0f
|
|
)
|
|
return false;
|
|
/*
|
|
if(a[0] < 0.0f
|
|
&&
|
|
a[1] < 0.0f
|
|
&&
|
|
a[2] < 0.0f
|
|
)
|
|
return false;
|
|
if(b[0] < 0.0f
|
|
&&
|
|
b[1] < 0.0f
|
|
&&
|
|
b[2] < 0.0f
|
|
)
|
|
return false;
|
|
if(a[0] > 1.0f
|
|
&&
|
|
a[1] > 1.0f
|
|
&&
|
|
a[2] > 1.0f
|
|
)
|
|
return false;
|
|
if(b[0] > 1.0f
|
|
&&
|
|
b[1] > 1.0f
|
|
&&
|
|
b[2] > 1.0f
|
|
)
|
|
return false;
|
|
*/
|
|
return true;
|
|
}
|
|
|
|
//tells weather a sphere colides with a triangle
|
|
bool shpere_tri_edge(vec3d* s_point, float rad, vertex vert[3]){
|
|
vec3d n;
|
|
float d;
|
|
for(int i = 0; i< 3; i++){
|
|
vec3d point_one;
|
|
vm_vert2vec(&vert[i], &point_one);
|
|
vec3d point_two;
|
|
vm_vert2vec(&vert[(i+1)%3], &point_two);
|
|
switch(vm_vec_dist_to_line(s_point, &point_one, &point_two, &n, NULL)){
|
|
// behind the line, so use the start pos
|
|
case -1:
|
|
d = vm_vec_dist(s_point,&point_one);
|
|
break;
|
|
|
|
// use the closest point
|
|
case 0:
|
|
d = vm_vec_dist(s_point,&n);
|
|
break;
|
|
|
|
// past the line, so use the shot pos
|
|
case 1:
|
|
d = vm_vec_dist(s_point,&point_two);
|
|
break;
|
|
default:
|
|
d = 0.0f;
|
|
Int3();
|
|
break;
|
|
}
|
|
|
|
Assert(d > 0);
|
|
if(d < rad)return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool decal_tmap_bbox(vec3d *test, float rad){
|
|
if(fl_abs(test->xyz.x) > rad)return false;
|
|
if(fl_abs(test->xyz.y) > rad)return false;
|
|
if(fl_abs(test->xyz.z) > rad)return false;
|
|
return true;
|
|
}
|
|
|
|
void decal_clip_line(vertex *out,vertex* p1, vertex* p2, float test, bool U){
|
|
//test is wich part of the UV plane were testing 0.0 or 1.0
|
|
//U is if were testing the u of the uv pair, if false then were testing v
|
|
float iterp = 0.0;
|
|
if(U)iterp = (p1->u - test)/(p1->u - p2->u);
|
|
else iterp = (p1->v - test)/(p1->v - p2->v);
|
|
out->x = ((p2->x-p1->x)*iterp)+p1->x*iterp;
|
|
out->y = ((p2->y-p1->y)*iterp)+p1->y*iterp;
|
|
out->z = ((p2->z-p1->z)*iterp)+p1->z*iterp;
|
|
if(U){
|
|
out->u = ((p2->u-p1->u)*iterp)+p1->u;
|
|
out->v = p1->v;;
|
|
}else{
|
|
out->u = p1->u;
|
|
out->v = ((p2->v-p1->v)*iterp)+p1->v;
|
|
}
|
|
}
|
|
|
|
int decal_clip_tri(vertex in[3], vertex out[20]){
|
|
vertex work[20];
|
|
memcpy(work, in, sizeof(vertex)*3);
|
|
int n_verts = 0;
|
|
int old_n_verts = 3;
|
|
int i;
|
|
|
|
for(i = 0; i<old_n_verts; i++){
|
|
//for each edge, in[i], in[(i+1)%3]
|
|
if((work[i].u <= 1.0f)){
|
|
//if the starting point is ok, copy it
|
|
out[n_verts++] = work[i];
|
|
|
|
if(!(work[(i+1)%old_n_verts].u <= 1.0f)){
|
|
//if the end point is bad, clip between them
|
|
decal_clip_line(&out[n_verts++], &work[i], &work[(i+1)%old_n_verts], 1.0f, true);
|
|
//don't clip between two bad points
|
|
}
|
|
}else if((work[(i+1)%old_n_verts].u <= 1.0f)){
|
|
//if the start point is bad, but the end point is good clip it
|
|
decal_clip_line(&out[n_verts++], &work[i], &work[(i+1)%old_n_verts], 1.0f, true);
|
|
//don't clip between two bad points
|
|
}
|
|
|
|
}
|
|
old_n_verts = n_verts;
|
|
n_verts = 0;
|
|
memcpy(work, out, sizeof(vertex)*20);
|
|
for( i = 0; i<old_n_verts; i++){
|
|
//for each edge, in[i], in[(i+1)%3]
|
|
if((work[i].u >= 0.0f)){
|
|
//if the starting point is ok, copy it
|
|
out[n_verts++] = work[i];
|
|
|
|
if(!(work[(i+1)%old_n_verts].u >= 0.0f)){
|
|
//if the end point is bad, clip between them
|
|
decal_clip_line(&out[n_verts++], &work[i], &work[(i+1)%old_n_verts], 0.0f, true);
|
|
//don't clip between two bad points
|
|
}
|
|
}else if((work[(i+1)%old_n_verts].u >= 0.0f) ){
|
|
//if the start point is bad, but the end point is good clip it
|
|
decal_clip_line(&out[n_verts++], &work[i], &work[(i+1)%old_n_verts], 0.0f, true);
|
|
//don't clip between two bad points
|
|
}
|
|
|
|
}
|
|
|
|
old_n_verts = n_verts;
|
|
n_verts = 0;
|
|
memcpy(work, out, sizeof(vertex)*20);
|
|
for( i = 0; i<old_n_verts; i++){
|
|
//for each edge, in[i], in[(i+1)%3]
|
|
if((work[i].v <= 1.0f)){
|
|
//if the starting point is ok, copy it
|
|
out[n_verts++] = work[i];
|
|
|
|
if(!(work[(i+1)%old_n_verts].v <= 1.0f)){
|
|
//if the end point is bad, clip between them
|
|
decal_clip_line(&out[n_verts++], &work[i], &work[(i+1)%old_n_verts], 1.0f, false);
|
|
//don't clip between two bad points
|
|
}
|
|
}else if((work[(i+1)%old_n_verts].v <= 1.0f) ){
|
|
//if the start point is bad, but the end point is good clip it
|
|
decal_clip_line(&out[n_verts++], &work[i], &work[(i+1)%old_n_verts], 1.0f, false);
|
|
//don't clip between two bad points
|
|
}
|
|
|
|
}
|
|
|
|
old_n_verts = n_verts;
|
|
n_verts = 0;
|
|
memcpy(work, out, sizeof(vertex)*20);
|
|
for( i = 0; i<old_n_verts; i++){
|
|
//for each edge, in[i], in[(i+1)%3]
|
|
if((work[i].v >= 0.0f)){
|
|
//if the starting point is ok, copy it
|
|
out[n_verts++] = work[i];
|
|
|
|
if(!(work[(i+1)%old_n_verts].v >= 0.0f)){
|
|
//if the end point is bad, clip between them
|
|
decal_clip_line(&out[n_verts++], &work[i], &work[(i+1)%old_n_verts], 0.0f, false);
|
|
//don't clip between two bad points
|
|
}
|
|
}else if((work[(i+1)%old_n_verts].v >= 0.0f) ){
|
|
//if the start point is bad, but the end point is good clip it
|
|
decal_clip_line(&out[n_verts++], &work[i], &work[(i+1)%old_n_verts], 0.0f, false);
|
|
//don't clip between two bad points
|
|
}
|
|
|
|
}
|
|
return n_verts;
|
|
}
|
|
|
|
float fvi_point_dist_plane(vec3d* pl_pnt, vec3d *pl_norm, vertex *vert){
|
|
vec3d vec;
|
|
vm_vert2vec(vert, &vec);
|
|
return fvi_point_dist_plane(pl_pnt, pl_norm, &vec);
|
|
}
|
|
|
|
int decal_plane_clip_tri(vertex in[3], vertex out[20]){
|
|
//decal_cube_plane[point][norm]
|
|
vertex work[20];
|
|
memcpy(work, in, sizeof(vertex)*3);
|
|
int n_verts = 0;
|
|
int old_n_verts = 3;
|
|
vec3d temp, temp2, temp3;
|
|
|
|
for(int p = 0; p<6; p++){
|
|
for(int i = 0; i<old_n_verts; i++){
|
|
//for each edge, in[i], in[(i+1)%3]
|
|
if(fvi_point_dist_plane(&decal_cube_plane[p][0], &decal_cube_plane[p][1], &work[i]) > 0.0){
|
|
//if the starting point is ok, copy it
|
|
out[n_verts++] = work[i];
|
|
|
|
if(!(fvi_point_dist_plane(&decal_cube_plane[p][0], &decal_cube_plane[p][1], &work[(i+1)%old_n_verts]) > 0.0)){
|
|
//if the end point is bad, clip between them
|
|
vm_vert2vec(&work[(i+1)%old_n_verts], &temp2);
|
|
vm_vert2vec(&work[i], &temp3);
|
|
fvi_segment_plane(&temp, &decal_cube_plane[p][0], &decal_cube_plane[p][1], &temp3, &temp2, 0.0f);
|
|
vm_vec2vert(&temp, &out[n_verts++]);
|
|
//don't clip between two bad points
|
|
}
|
|
}else if(fvi_point_dist_plane(&decal_cube_plane[p][0], &decal_cube_plane[p][1], &work[(i+1)%old_n_verts]) > 0.0){
|
|
//if the start point is bad, but the end point is good clip it
|
|
vm_vert2vec(&work[i], &temp3);
|
|
vm_vert2vec(&work[(i+1)%old_n_verts], &temp2);
|
|
fvi_segment_plane(&temp, &decal_cube_plane[p][0], &decal_cube_plane[p][1], &temp3, &temp2, 0.0f);
|
|
vm_vec2vert(&temp, &out[n_verts++]);
|
|
//don't clip between two bad points
|
|
}
|
|
|
|
}
|
|
old_n_verts = n_verts;
|
|
n_verts = 0;
|
|
memcpy(work, out, sizeof(vertex)*20);
|
|
}
|
|
return old_n_verts;
|
|
}
|
|
|
|
// Textured Poly
|
|
// +0 int id
|
|
// +4 int size
|
|
// +8 vec3d normal
|
|
// +20 vec3d normal_point
|
|
// +32 int radius
|
|
// +36 int nverts
|
|
// +40 int tmap_num
|
|
// +44 nverts*(model_tmap_vert) vertlist (n,u,v)
|
|
void decal_create_tmappoly(ubyte * p)
|
|
{
|
|
|
|
// mprintf(("entering decal_create_tmappoly\n"));
|
|
|
|
|
|
|
|
bool clip = true;
|
|
int i;
|
|
int nv;
|
|
// uv_pair uvlist[TMAP_MAX_VERTS];
|
|
vec3d *points[TMAP_MAX_VERTS];
|
|
model_tmap_vert *verts;
|
|
|
|
nv = dw(p+36);
|
|
if ( nv < 0 ) return;
|
|
|
|
if ( nv > TMAP_MAX_VERTS ) {
|
|
Int3();
|
|
return;
|
|
}
|
|
|
|
//TIMERBAR_PUSH(TIMERBAR_WHITE);
|
|
verts = (model_tmap_vert *)(p+44);
|
|
|
|
for (i=0;i<nv;i++) {
|
|
decal__poly[i] = (int)verts[i].vertnum;
|
|
points[i] = decal_point_list[decal__poly[i]];
|
|
}
|
|
|
|
vec3d *pnorm = dvp(p+8);
|
|
vec3d norm = *pnorm;
|
|
vm_vec_normalize(&norm);
|
|
|
|
//float back = 1.0;
|
|
|
|
// if( (back_faceing == 0) && (back < 0) )return;
|
|
|
|
//poly culling
|
|
vec3d *pcenter = (vec3d*)(p+20);
|
|
float pradius = *(float*)(p+32);
|
|
vec3d dir_to_dec;
|
|
vm_vec_sub(&dir_to_dec, pcenter, &decal_hit_point);
|
|
vm_vec_normalize(&dir_to_dec);
|
|
float dot = vm_vec_dot(&decal_hit_vect, &norm);
|
|
|
|
if(dot > -0.005){
|
|
// TIMERBAR_POP();
|
|
return;
|
|
}
|
|
/* float dist = 0;
|
|
for (i=0;i<nv;i++) {
|
|
dist = vm_vec_dist(decal_point_list[decal__poly[i]], &pcenter);
|
|
if(dist>pradius){
|
|
pradius = dist;
|
|
}
|
|
}
|
|
*/
|
|
float decal_plane_dist = fl_abs(fvi_point_dist_plane(pcenter, pnorm, &decal_hit_point));
|
|
if(decal_plane_dist > max_rad*1.5f){
|
|
// TIMERBAR_POP();
|
|
return;
|
|
}
|
|
|
|
vec3d closest;
|
|
vm_project_point_onto_plane(&closest, &decal_hit_point, &norm, pcenter);
|
|
|
|
if(clip && !fvi_point_face(&closest, nv, points, &norm, NULL, NULL, NULL)){
|
|
// if the point isn't on the face, find the line segment it is closest to
|
|
//and make that point the closest
|
|
float distance = FLT_MAX, test_dist = FLT_MAX;
|
|
vec3d nearest = closest, test_nearest;
|
|
for(i = 0; i<nv; i++){
|
|
switch (vm_vec_dist_to_line(&closest,decal_point_list[decal__poly[i]],decal_point_list[decal__poly[(i+1)%nv]],&test_nearest, &test_dist)){
|
|
case -1:
|
|
if(test_dist < distance){
|
|
nearest = *decal_point_list[decal__poly[i]];
|
|
distance = test_dist;
|
|
}
|
|
break;
|
|
case 0:
|
|
if(test_dist < distance){
|
|
nearest = test_nearest;
|
|
distance = test_dist;
|
|
}
|
|
break;
|
|
case 1:
|
|
if(test_dist < distance){
|
|
nearest = *decal_point_list[decal__poly[(i+1)%nv]];
|
|
distance = test_dist;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
closest = nearest;
|
|
}
|
|
|
|
vec3d local_closest;
|
|
if(clip){
|
|
vm_vec_sub(&local_closest, &closest, &decal_hit_point);
|
|
vec3d ctemp = local_closest;
|
|
vm_vec_rotate(&local_closest,&ctemp, &decal_orient);
|
|
}
|
|
|
|
bool defenately = !clip || (decal_tmap_bbox(&local_closest, decal_min_hit_radius));
|
|
|
|
if(!defenately && max_rad*1.5 < vm_vec_dist(&closest, &decal_hit_point)){
|
|
mprintf(("bugging out becase closest is out of max_rad\n"));
|
|
// TIMERBAR_POP();
|
|
return;
|
|
}
|
|
decal* set_decal = new_decal;
|
|
if(set_decal->n_poly >= MAX_DECAL_POLY-1){
|
|
mprintf(("bugging out becase there are too many polys in the decal\n"));
|
|
// TIMERBAR_POP();
|
|
return;
|
|
}
|
|
vertex work_poly[20];
|
|
if(nv > 2){
|
|
// decal_poly *poly = set_decal->get_last_poly();
|
|
if(clip){
|
|
//cliped decals
|
|
for (i=1;i<(nv-1);i++) {
|
|
if(set_decal->n_poly >= MAX_DECAL_POLY-1){
|
|
mprintf(("bugging out becase there are too many polys in the decal\n"));
|
|
// TIMERBAR_POP();
|
|
return;
|
|
}
|
|
|
|
Assert(decal_points_allocated >= i%nv);
|
|
Assert(decal_points_allocated >= (i+1)%nv);
|
|
Assert(decal_points_allocated >= decal__poly[0]);
|
|
Assert(decal_points_allocated >= decal__poly[i%nv]);
|
|
Assert(decal_points_allocated >= decal__poly[(i+1)%nv]);
|
|
|
|
vm_vec2vert(decal_point_list[decal__poly[0]], &LAST_POLY->point[0]);
|
|
vm_vec2vert(decal_point_list[decal__poly[i%nv]], &LAST_POLY->point[1]);
|
|
vm_vec2vert(decal_point_list[decal__poly[(i+1)%nv]], &LAST_POLY->point[2]);
|
|
LAST_POLY->norm[0] = norm;
|
|
LAST_POLY->norm[1] = norm;
|
|
LAST_POLY->norm[2] = norm;
|
|
// set_decal->poly[set_decal->n_poly].norm = norm;
|
|
// set_decal->n_poly++;
|
|
int k;
|
|
float a[3], b[3];
|
|
for (k=0;k<3;k++) {
|
|
vec3d temp;
|
|
vm_vert2vec(&LAST_POLY->point[k], &temp);
|
|
b[k] = (fvi_point_dist_plane(&decal_cube_plane[4][0], &decal_cube_plane[4][1], &temp) / (max_rad*3));
|
|
a[k] = (fvi_point_dist_plane(&decal_cube_plane[5][0], &decal_cube_plane[5][1], &temp) / (max_rad*3));
|
|
}
|
|
for ( k=0;k<3;k++) {
|
|
//calculate the UV coords
|
|
vec3d temp;
|
|
vm_vert2vec(&LAST_POLY->point[k], &temp);
|
|
LAST_POLY->point[k].u = (fvi_point_dist_plane(&decal_cube_plane[0][0], &decal_cube_plane[0][1], &temp) / (min_rad*2));
|
|
LAST_POLY->point[k].v = (fvi_point_dist_plane(&decal_cube_plane[2][0], &decal_cube_plane[2][1], &temp) / (min_rad*2));
|
|
}
|
|
// bool uv_passed = check_uv(LAST_POLY);
|
|
// mprintf(("decal poly %d, vert 0 being set to %d, vert 1 %d, and vert 2 %d\n", set_decal->n_poly, new_decal->poly[set_decal->n_poly].point[0], new_decal->poly[set_decal->n_poly].point[1], new_decal->poly[set_decal->n_poly].point[2]));
|
|
int work_n_verts = 0;;
|
|
/*if(uv_passed)*/{
|
|
if(pradius > max_rad){
|
|
work_n_verts = decal_plane_clip_tri(LAST_POLY->point, work_poly);
|
|
}else{
|
|
memcpy(work_poly, LAST_POLY->point, sizeof(vertex)*3);
|
|
work_n_verts = 3;
|
|
}
|
|
for( int j = 1; j < work_n_verts-1; j++){
|
|
|
|
LAST_POLY->point[0] = work_poly[0];
|
|
LAST_POLY->point[1] = work_poly[j];
|
|
LAST_POLY->point[2] = work_poly[(j+1)%work_n_verts];
|
|
|
|
for ( k=0;k<3;k++) {
|
|
//calculate the UV coords
|
|
vec3d temp;
|
|
vm_vert2vec(&LAST_POLY->point[k], &temp);
|
|
LAST_POLY->point[k].u = (fvi_point_dist_plane(&decal_cube_plane[0][0], &decal_cube_plane[0][1], &temp) / (min_rad*2));
|
|
LAST_POLY->point[k].v = (fvi_point_dist_plane(&decal_cube_plane[2][0], &decal_cube_plane[2][1], &temp) / (min_rad*2));
|
|
}
|
|
|
|
bool uv_passed = check_uv(LAST_POLY);
|
|
if(defenately){
|
|
LAST_POLY = set_decal->add_poly();
|
|
mprintf(("there are now %d polys in the current decal\n", set_decal->n_poly));
|
|
}else
|
|
if(uv_passed && IS_VEC_NULL(&local_closest)){
|
|
//if local_closest is null than the poly is coplaner to the poly that was hit,
|
|
//only if it's UVs are out of range would it not count
|
|
LAST_POLY = set_decal->add_poly();
|
|
mprintf(("there are now %d polys in the current decal\n", set_decal->n_poly));
|
|
}else
|
|
if(uv_passed && check_ab(a,b)){
|
|
LAST_POLY = set_decal->add_poly();
|
|
mprintf(("there are now %d polys in the current decal\n", set_decal->n_poly));
|
|
}/*else
|
|
if(shpere_tri_edge(&decal_hit_point, decal_min_hit_radius, LAST_POLY->point)){
|
|
LAST_POLY = set_decal->add_poly();
|
|
mprintf(("there are now %d polys in the current decal, sphere colide\n", set_decal->n_poly));
|
|
}else
|
|
if(shpere_tri_edge(&decal_hit_point, decal_hit_radius, LAST_POLY->point)){
|
|
LAST_POLY = set_decal->add_poly();
|
|
mprintf(("there are now %d polys in the current decal, big sphere colide\n", set_decal->n_poly));
|
|
}*/
|
|
}
|
|
}
|
|
}
|
|
}else{
|
|
for (i=1;i<(nv-1);i++) {
|
|
// for (int k=0;k<3;k++) {
|
|
//calculate the UV coords
|
|
vm_vec2vert(decal_point_list[decal__poly[0]], &LAST_POLY->point[0]);
|
|
vec3d temp;
|
|
vm_vert2vec(&LAST_POLY->point[0], &temp);
|
|
LAST_POLY->point[0].u = (fvi_point_dist_plane(&decal_cube_plane[0][0], &decal_cube_plane[0][1], &temp) / (min_rad*2));
|
|
LAST_POLY->point[0].v = (fvi_point_dist_plane(&decal_cube_plane[2][0], &decal_cube_plane[2][1], &temp) / (min_rad*2));
|
|
|
|
vm_vec2vert(decal_point_list[decal__poly[i]], &LAST_POLY->point[1]);
|
|
vm_vert2vec(&LAST_POLY->point[1], &temp);
|
|
LAST_POLY->point[1].u = (fvi_point_dist_plane(&decal_cube_plane[0][0], &decal_cube_plane[0][1], &temp) / (min_rad*2));
|
|
LAST_POLY->point[1].v = (fvi_point_dist_plane(&decal_cube_plane[2][0], &decal_cube_plane[2][1], &temp) / (min_rad*2));
|
|
|
|
vm_vec2vert(decal_point_list[decal__poly[(i+1)%nv]], &LAST_POLY->point[2]);
|
|
vm_vert2vec(&LAST_POLY->point[2], &temp);
|
|
LAST_POLY->point[2].u = (fvi_point_dist_plane(&decal_cube_plane[0][0], &decal_cube_plane[0][1], &temp) / (min_rad*2));
|
|
LAST_POLY->point[2].v = (fvi_point_dist_plane(&decal_cube_plane[2][0], &decal_cube_plane[2][1], &temp) / (min_rad*2));
|
|
|
|
// }
|
|
bool uv_passed = check_uv(LAST_POLY);
|
|
if(defenately){
|
|
LAST_POLY = set_decal->add_poly();
|
|
mprintf(("there are now %d polys in the current decal\n", set_decal->n_poly));
|
|
}else
|
|
if(uv_passed && IS_VEC_NULL(&local_closest)){
|
|
//if local_closest is null than the poly is coplaner to the poly that was hit,
|
|
//only if it's UVs are out of range would it not count
|
|
LAST_POLY = set_decal->add_poly();
|
|
mprintf(("there are now %d polys in the current decal\n", set_decal->n_poly));
|
|
}
|
|
}
|
|
}
|
|
}else{
|
|
// mprintf(("no poly, all points are out side of planes"));
|
|
}
|
|
|
|
//TIMERBAR_POP();
|
|
}
|
|
|
|
|
|
int decal_create_sub(void *model_ptr )
|
|
{
|
|
|
|
// mprintf(("plane 0 position is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[0][0].xyz.x, decal_cube_plane[0][0].xyz.y, decal_cube_plane[0][0].xyz.z));
|
|
// mprintf(("plane 0 normal is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[0][1].xyz.x, decal_cube_plane[0][1].xyz.y, decal_cube_plane[0][1].xyz.z));
|
|
|
|
// mprintf(("entering decal_create_sub\n"));
|
|
|
|
ubyte *p = (ubyte *)model_ptr;
|
|
int chunk_type, chunk_size;
|
|
|
|
chunk_type = dw(p);
|
|
chunk_size = dw(p+4);
|
|
|
|
// mprintf(("plane 0 position is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[0][0].xyz.x, decal_cube_plane[0][0].xyz.y, decal_cube_plane[0][0].xyz.z));
|
|
// mprintf(("plane 0 normal is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[0][1].xyz.x, decal_cube_plane[0][1].xyz.y, decal_cube_plane[0][1].xyz.z));
|
|
|
|
|
|
while (chunk_type != DP_EOF) {
|
|
|
|
// mprintf(( "Processing chunk type %d, len=%d\n", chunk_type, chunk_size ));
|
|
// mprintf(("plane 0 position is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[0][0].xyz.x, decal_cube_plane[0][0].xyz.y, decal_cube_plane[0][0].xyz.z));
|
|
// mprintf(("plane 0 normal is x %0.2f y %0.2f z %0.2f\n", decal_cube_plane[0][1].xyz.x, decal_cube_plane[0][1].xyz.y, decal_cube_plane[0][1].xyz.z));
|
|
|
|
|
|
switch (chunk_type) {
|
|
case DP_EOF: return 1;
|
|
case DP_DEFPOINTS: decal_create_defpoints(p); break;
|
|
case DP_FLATPOLY: break;// I don't want any of these anyway-Bobboau decal_create_flatpoly(p); break;
|
|
case DP_TMAPPOLY: decal_create_tmappoly(p); break;
|
|
case DP_SORTNORM: decal_create_sortnorm(p); break;
|
|
case DP_BOUNDBOX:
|
|
/* if (!mc_ray_boundingbox( vp(p+8), vp(p+20), &Mc_p0, &Mc_direction, NULL )) {
|
|
return 1;
|
|
}*/
|
|
break;
|
|
default:
|
|
mprintf(( "Bad chunk type %d, len=%d in decal_create_sub\n", chunk_type, chunk_size ));
|
|
Int3(); // Bad chunk type!
|
|
return 0;
|
|
}
|
|
// mprintf(( "current chunk offset %d\n", (int)p ));
|
|
|
|
p += chunk_size;
|
|
chunk_type = dw(p);
|
|
chunk_size = dw(p+4);
|
|
}
|
|
|
|
|
|
return 1;
|
|
}
|
|
|
|
poly_list dec_list;
|
|
|
|
//finds the tri count of the current decal list
|
|
int find_decal_tricounts(decal_system* system, int i){
|
|
int dec_tri_count = 0;
|
|
decal_list_controle* list = &system->decals[i];
|
|
decal_list* decal = list->d_list;
|
|
decal_list* d;
|
|
#ifndef NDEBUG
|
|
int n = list->n_decals;
|
|
#endif
|
|
while(decal != NULL){
|
|
Assert(n--);
|
|
Assert((decal->dec.n_poly < MAX_DECAL_POLY) && (decal->dec.n_poly > -1));
|
|
dec_tri_count += decal->dec.n_poly;
|
|
d = decal;
|
|
decal = decal->next;
|
|
}
|
|
Assert(d == list->end);
|
|
return dec_tri_count;
|
|
}
|
|
|
|
//decal *temp_decals[MAX_SHIP_DECAL_TEXTURES][MAX_SHIP_DECALS]; //the decals of the ship
|
|
/*
|
|
int find_decal_texture_index(int t, int texture[MAX_SHIP_DECAL_TEXTURES]){
|
|
for(int i = 0; i<MAX_SHIP_DECAL_TEXTURES; i++)if(texture[i] == t)return i;
|
|
return-1;
|
|
}
|
|
*/
|
|
void rebuild_decal_buffer(decal_system* system){
|
|
SAFEPOINT("entering rebuild_decal_buffer");
|
|
|
|
for(int i = 0; i<system->n_decal_textures; i++){
|
|
check_ship_decals();
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
decal_list_controle* list = &system->decals[i];
|
|
if(!list)continue;
|
|
|
|
if(!list->modifyed){
|
|
continue; //if this list hasn't been modifyed don't bother
|
|
}
|
|
|
|
decal_list* decl = list->d_list;
|
|
dec_list.allocate(find_decal_tricounts(system, i)*3);
|
|
|
|
decal_list* d;
|
|
dec_list.n_verts = 0;
|
|
list->n_poly = 0;
|
|
while(decl != NULL){
|
|
decal *dec = &decl->dec;
|
|
Assert((dec->n_poly < MAX_DECAL_POLY) && (dec->n_poly > -1));
|
|
if(dec->n_poly == MAX_DECAL_POLY-1)
|
|
mprintf(( "decal maxed out, decal creation probly isn't working right\n"));
|
|
if(dec->n_poly == 0)
|
|
mprintf(( "decal empty, decal creation failed\n"));
|
|
|
|
decal_poly* poly = dec->poly;
|
|
dec->vertex_buffer_start = dec_list.n_verts;
|
|
for(int j = 0; j < dec->n_poly; j++){
|
|
dec_list.vert[dec_list.n_verts] = poly->point[0];
|
|
dec_list.norm[dec_list.n_verts] = poly->norm[0];
|
|
|
|
dec_list.vert[dec_list.n_verts + 1] = poly->point[1];
|
|
dec_list.norm[dec_list.n_verts + 1] = poly->norm[1];
|
|
|
|
dec_list.vert[dec_list.n_verts + 2] = poly->point[2];
|
|
dec_list.norm[dec_list.n_verts + 2] = poly->norm[2];
|
|
|
|
poly = poly->next;
|
|
|
|
dec_list.n_verts += 3;
|
|
list->n_poly++;
|
|
}
|
|
d = decl;
|
|
decl = decl->next;
|
|
}
|
|
Assert(d == list->end);
|
|
|
|
Assert(list->end->dec.vertex_buffer_start + (list->end->dec.n_poly*3) <= dec_list.n_verts);
|
|
|
|
if(list->buffer > -1)gr_destroy_buffer(list->buffer);
|
|
if(dec_list.n_verts)list->buffer = gr_make_buffer(&dec_list, VERTEX_FLAG_POSITION | VERTEX_FLAG_NORMAL | VERTEX_FLAG_UV1);
|
|
else {
|
|
//n Warning(LOCATION, "no polys in the poly list!");
|
|
list->buffer = -1;
|
|
}
|
|
|
|
list->modifyed = false; //becase now the vertex buffer is in sync with what the decal list has
|
|
}
|
|
|
|
system->decals_modified = false;
|
|
check_ship_decals();
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
|
|
SAFEPOINT("leaveing rebuild_decal_buffer");
|
|
}
|
|
|
|
/*
|
|
void decal_render_all(object * obj)
|
|
{
|
|
if(obj->type != OBJ_SHIP){
|
|
return;
|
|
}
|
|
|
|
ship *shipp = &Ships[obj->instance];
|
|
if(shipp->decals_modified)rebuild_decal_buffer(obj);
|
|
gr_set_texture_addressing(TMAP_ADDRESS_CLAMP);
|
|
gr_zbias(3);
|
|
for(int i = 0; i<shipp->n_decal_textures; i++){
|
|
gr_set_bitmap( shipp->decals[i].texture, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0 );
|
|
if(shipp->decals[i].buffer != -1)gr_render_buffer(shipp->decals[i].buffer);
|
|
|
|
}
|
|
gr_zbias(0);
|
|
gr_set_texture_addressing(TMAP_ADDRESS_WRAP);
|
|
}
|
|
*/
|
|
|
|
extern int GLOWMAP;
|
|
void decal_render_system(decal_system* system){
|
|
//return;
|
|
int i;
|
|
|
|
if(system->decals_modified)rebuild_decal_buffer(system);
|
|
gr_zbias(4);
|
|
for(i = 0; i<system->n_decal_textures; i++){
|
|
GLOWMAP = system->decals[i].glow_texture;
|
|
gr_set_bitmap( system->decals[i].texture, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0 );
|
|
if(system->decals[i].buffer != -1){
|
|
gr_set_buffer(system->decals[i].buffer);
|
|
gr_render_buffer(0, system->decals[i].n_poly, NULL);
|
|
}
|
|
}
|
|
GLOWMAP = -1;
|
|
SAFEPOINT("begining decal burn pass");
|
|
if(!Cmdline_nohtl)gr_set_lighting(false,true);
|
|
gr_zbias(5);
|
|
for( i = 0; i<system->n_decal_textures; i++){
|
|
decal_list *list = system->decals[i].d_list;
|
|
int verts_used = 0;
|
|
if(system->decals[i].buffer != -1){
|
|
gr_set_buffer(system->decals[i].buffer);
|
|
while(list != NULL){
|
|
// if it's too old prune it
|
|
if(list->dec.timestamp + list->dec.burn_time > timestamp()){
|
|
//if it's still alive render it
|
|
Assert(list->dec.n_poly > 0 && list->dec.vertex_buffer_start > -1);
|
|
Assert(list->dec.vertex_buffer_start == 3*(list->dec.vertex_buffer_start/3));
|
|
if(!list->dec.n_poly)continue;
|
|
if(list->dec.vertex_buffer_start < 0)continue;
|
|
float a = 1.0f - ( (float(timestamp()) - float(list->dec.timestamp)) / float(list->dec.burn_time) );
|
|
gr_set_bitmap( system->decals[i].burn_texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, a );
|
|
gr_render_buffer(verts_used, list->dec.n_poly, NULL);
|
|
}
|
|
verts_used += list->dec.n_poly * 3;
|
|
list = list->next;
|
|
}
|
|
}
|
|
}
|
|
gr_zbias(0);
|
|
}
|
|
|
|
int decal_submodel_instance_depth = 0;
|
|
void set_submodel_instance(int model_num, int sub_model_num){
|
|
Assert(!decal_submodel_instance_depth);
|
|
polymodel *pm = model_get(model_num);
|
|
|
|
angles orient[8];//probly only need 2 or 3, but what the hell
|
|
vec3d offset[8];
|
|
|
|
while ((sub_model_num >= 0) && (pm->submodel[sub_model_num].parent >= 0) ) {
|
|
|
|
orient[decal_submodel_instance_depth] = pm->submodel[sub_model_num].angs;
|
|
offset[decal_submodel_instance_depth] = pm->submodel[sub_model_num].offset;
|
|
decal_submodel_instance_depth++;
|
|
|
|
sub_model_num = pm->submodel[sub_model_num].parent;
|
|
if(decal_submodel_instance_depth == 7)break;
|
|
}
|
|
for(int i = 0; i < decal_submodel_instance_depth; i++){
|
|
g3_start_instance_angles(&offset[i], &orient[i]);
|
|
}
|
|
}
|
|
|
|
void end_submodel_instance(){
|
|
while(decal_submodel_instance_depth > 0){
|
|
decal_submodel_instance_depth--;
|
|
g3_done_instance(true);
|
|
}
|
|
Assert(!decal_submodel_instance_depth);
|
|
}
|
|
|
|
void decal_render_all(object * obj)
|
|
{
|
|
if(!Cmdline_decals)return;
|
|
// return;
|
|
|
|
// TIMERBAR_PUSH(TIMERBAR_DARKGREEN);
|
|
/*check_ship_decals();
|
|
check_list_decals();
|
|
check_poly_decals();*/
|
|
SAFEPOINT("entering decal render");
|
|
if(obj->type != OBJ_SHIP){
|
|
return;
|
|
}
|
|
gr_set_texture_addressing(TMAP_ADDRESS_CLAMP);
|
|
gr_zbuffer_set(GR_ZBUFF_READ);
|
|
|
|
ship *shipp = &Ships[obj->instance];
|
|
decal_system* system = &shipp->ship_decal_system;
|
|
|
|
decal_render_system(system);
|
|
|
|
ship_subsys *sys = GET_FIRST(&shipp->subsys_list);;
|
|
|
|
// ship_model_start(obj); //were allready in
|
|
|
|
// TIMERBAR_PUSH(TIMERBAR_LIGHTGREY);
|
|
while(sys != END_OF_LIST(&shipp->subsys_list)){
|
|
model_subsystem* psub = sys->system_info;
|
|
if(!psub){
|
|
sys = GET_NEXT(sys);
|
|
continue;
|
|
}
|
|
set_submodel_instance(psub->model_num, psub->subobj_num);
|
|
decal_render_system(&psub->model_decal_system);
|
|
end_submodel_instance();
|
|
|
|
sys = GET_NEXT(sys);
|
|
}
|
|
// TIMERBAR_POP();
|
|
|
|
// ship_model_stop(obj);
|
|
|
|
gr_set_texture_addressing(TMAP_ADDRESS_WRAP);
|
|
|
|
SAFEPOINT("leaveing decal render");
|
|
// TIMERBAR_POP();
|
|
/*check_ship_decals();
|
|
check_list_decals();
|
|
check_poly_decals();
|
|
*/
|
|
}
|
|
|