diff --git a/include/XPMPMultiplayer.h b/include/XPMPMultiplayer.h index c1bd2b707..0f18f8543 100644 --- a/include/XPMPMultiplayer.h +++ b/include/XPMPMultiplayer.h @@ -442,6 +442,7 @@ typedef void (* XPMPPlaneNotifier_f)( * */ typedef void (* XPMPRenderPlanes_f)( + int inIsBlend, void * inRef); /* diff --git a/include/XPMPPlaneRenderer.h b/include/XPMPPlaneRenderer.h index f19e0dc95..e4dcfc401 100644 --- a/include/XPMPPlaneRenderer.h +++ b/include/XPMPPlaneRenderer.h @@ -29,6 +29,6 @@ // These functions do "the drawing" once per frame. void XPMPInitDefaultPlaneRenderer(void); -void XPMPDefaultPlaneRenderer(void); +void XPMPDefaultPlaneRenderer(int is_blend); #endif \ No newline at end of file diff --git a/src/XPMPMultiplayer.cpp b/src/XPMPMultiplayer.cpp index f2976441a..67df3b4f6 100644 --- a/src/XPMPMultiplayer.cpp +++ b/src/XPMPMultiplayer.cpp @@ -33,6 +33,7 @@ #include "XPLMProcessing.h" #include "XPLMPlanes.h" +#include "XPLMDataAccess.h" #include "XPLMDisplay.h" #include "XPLMPlugin.h" #include "XPLMUtilities.h" @@ -476,10 +477,22 @@ int XPMPRenderMultiplayerPlanes( int inIsBefore, void * inRefcon) { + static int is_blend = 0; + + static XPLMDataRef wrt = XPLMFindDataRef("sim/graphics/view/world_render_type"); + static XPLMDataRef prt = XPLMFindDataRef("sim/graphics/view/plane_render_type"); + + int is_shadow = wrt != NULL && XPLMGetDatai(wrt) != 0; + + if(prt) + is_blend = XPLMGetDatai(prt) == 2; + if (gRenderer) - gRenderer(gRendererRef); + gRenderer(is_shadow ? 0 : is_blend,gRendererRef); else - XPMPDefaultPlaneRenderer(); + XPMPDefaultPlaneRenderer(is_shadow ? 0 : is_blend); + if(!is_shadow) + is_blend = 1 - is_blend; return 1; } diff --git a/src/XPMPMultiplayerCSL.cpp b/src/XPMPMultiplayerCSL.cpp index 776081c0f..ca6266fd2 100644 --- a/src/XPMPMultiplayerCSL.cpp +++ b/src/XPMPMultiplayerCSL.cpp @@ -256,6 +256,7 @@ static bool LoadOnePackage(const string& inPath, int pass); bool CSL_Init( const char* inTexturePath) { + obj_init(); bool ok = OBJ_Init(inTexturePath); if (!ok) XPLMDump() << "XSB WARNING: we failed to find XSB's custom lighting texture at " << inTexturePath << ".\n"; @@ -326,6 +327,10 @@ bool LoadOnePackage(const string& inPath, int pass) BreakStringPvt(line, tokens, 4, " \t\r\n"); + //---------------------------------------------------------------------------------------------------- + // PACKAGE MANAGEMENT + //---------------------------------------------------------------------------------------------------- + // EXPORT_NAME if (!tokens.empty() && tokens[0] == "EXPORT_NAME" && pass == pass_Depend) { @@ -362,6 +367,9 @@ bool LoadOnePackage(const string& inPath, int pass) } } + //---------------------------------------------------------------------------------------------------- + // AUSTIN OLD SCHOOL ACFS + //---------------------------------------------------------------------------------------------------- // AIRCAFT if (!tokens.empty() && tokens[0] == "AIRCRAFT" && pass == pass_Load) @@ -395,6 +403,10 @@ bool LoadOnePackage(const string& inPath, int pass) XPLMDump(path, lineNum, line) << "XSB WARNING: AIRCRAFT command takes 3 arguments.\n"; } } + + //---------------------------------------------------------------------------------------------------- + // OBJ7 DRAWN WITH OUR CODE + //---------------------------------------------------------------------------------------------------- // OBJECT if (!tokens.empty() && tokens[0] == "OBJECT" && pass == pass_Load) @@ -432,7 +444,6 @@ bool LoadOnePackage(const string& inPath, int pass) } } - // TEXTURE if (!tokens.empty() && tokens[0] == "TEXTURE" && pass == pass_Load) { @@ -466,6 +477,109 @@ bool LoadOnePackage(const string& inPath, int pass) } } } + + //---------------------------------------------------------------------------------------------------- + // OBJ8 MULTI-OBJ WITH SIM RENDERING + //---------------------------------------------------------------------------------------------------- + + // OBJ8_AIRCRAFT + if (!tokens.empty() && tokens[0] == "OBJ8_AIRCRAFT" && pass == pass_Load) + { + BreakStringPvt(line, tokens, 2, " \t\r\n"); + + if(tokens.size() == 2) + { + pckg->planes.push_back(CSLPlane_t()); + pckg->planes.back().plane_type = plane_Obj8; + pckg->planes.back().file_path = tokens[1]; // debug str + pckg->planes.back().moving_gear = true; + pckg->planes.back().texID = 0; + pckg->planes.back().texLitID = 0; + pckg->planes.back().obj_idx = -1; + } + else + { + parse_err = true; + XPLMDump(path, lineNum, line) << "XSB WARNING: OBJ8_AIRCARFT command takes 1 argument.\n"; + } + } + + // OBJ8 + if (!tokens.empty() && tokens[0] == "OBJ8" && pass == pass_Load) + { + BreakStringPvt(line, tokens, 4, " \t\r\n"); + + if(tokens.size() == 4) + { + if(pckg->planes.empty() || pckg->planes.back().plane_type != plane_Obj8) + { + // err - obj8 record at stupid place in file + } + else + { + + obj_for_acf att; + + if(tokens[1] == "GLASS") + att.draw_type = draw_glass; + else if(tokens[1] == "LIGHTS") + att.draw_type = draw_lights; + else if(tokens[1] == "LOW_LOD") + att.draw_type = draw_low_lod; + else if(tokens[1] == "SOLID") + att.draw_type = draw_solid; + else { + // err crap enum + } + + if(tokens[2] == "YES") + att.needs_animation = true; + else if(tokens[2] == "NO") + att.needs_animation = false; + else + { + // crap flag + } + std::string fullPath = tokens[3]; + + MakePartialPathNativeObj(fullPath); + if (!DoPackageSub(fullPath)) + { + XPLMDump(path, lineNum, line) << "XSB WARNING: package not found.\n"; + parse_err = true; + } + + char xsystem[1024]; + XPLMGetSystemPath(xsystem); + + #if APL + HFS2PosixPath(xsystem, xsystem, 1024); + #endif + + int sys_len = strlen(xsystem); + if(fullPath.size() > sys_len) + fullPath.erase(fullPath.begin(),fullPath.begin() + sys_len); + else + { + // should probaby freak out here. + } + + att.handle = NULL; + att.file = fullPath; + + pckg->planes.back().attachments.push_back(att); + } + } + else + { + // err - f---ed line. + } + } + + //---------------------------------------------------------------------------------------------------- + // MATCHING CRAP AND OTHER COMMON META-DATA + //---------------------------------------------------------------------------------------------------- + // HASGEAR YES|NO // This line specifies whether the previous plane has retractable gear. @@ -487,7 +601,7 @@ bool LoadOnePackage(const string& inPath, int pass) } } } - + // ICAO // This line maps one ICAO code to the previous airline, without // specifying an airline or livery. @@ -978,7 +1092,7 @@ void CSL_DrawObject( XPLMPlaneDrawState_t * state) { // Setup OpenGL for this plane render - if(type < plane_Count) + if(type != plane_Obj8) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); @@ -1012,7 +1126,21 @@ void CSL_DrawObject( x, y ,z, pitch, roll, heading, lights); break; + case plane_Obj8: + obj_schedule_one_aircraft( + model, + x, + y, + z, + pitch, + roll, + heading, + full, // + lights, + state); + break; } - glPopMatrix(); + if(type != plane_Obj8) + glPopMatrix(); } diff --git a/src/XPMPMultiplayerObj8.cpp b/src/XPMPMultiplayerObj8.cpp new file mode 100644 index 000000000..48551b1d1 --- /dev/null +++ b/src/XPMPMultiplayerObj8.cpp @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2013, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "XPMPMultiplayerObj8.h" +#include "XPMPMultiplayerVars.h" +#include "XPLMScenery.h" +#include "XPLMUtilities.h" +#include "XPLMDataAccess.h" +#include +#include +using namespace std; + + +struct one_inst { + one_inst * next; + + XPLMDrawInfo_t location; + xpmp_LightStatus lights; + XPLMPlaneDrawState_t * state; + + ~one_inst() { delete next; } +}; + +struct one_obj { + one_obj * next; + obj_for_acf * model; + one_inst * head; + + ~one_obj() { delete head; delete next; } +}; + +static one_obj * s_worklist = NULL; + + +static one_inst * s_cur_plane = NULL; + +enum { + gear_rat = 0, + flap_rat, + spoi_rat, + sbrk_rat, + slat_rat, + swep_rat, + thrs_rat, + ptch_rat, + head_rat, + roll_rat, + + lan_lite_on, + bcn_lite_on, + str_lite_on, + nav_lite_on, + + dref_dim +}; + +const char * dref_names[dref_dim] = { + "libxplanemp/controls/gear_ratio", + "libxplanemp/controls/flap_ratio", + "libxplanemp/controls/spoiler_ratio", + "libxplanemp/controls/speed_brake_ratio", + "libxplanemp/controls/slat_ratio", + "libxplanemp/controls/wing_sweep_ratio", + "libxplanemp/controls/thrust_ratio", + "libxplanemp/controls/yoke_pitch_ratio", + "libxplanemp/controls/yoke_heading_ratio", + "libxplanemp/controls/yoke_roll_ratio", + + "libxplanemp/controls/landing_lites_on", + "libxplanemp/controls/beacon_lites_on", + "libxplanemp/controls/strobe_lites_on", + "libxplanemp/controls/nav_lites_on" +}; + + +static float obj_get_float(void * inRefcon) +{ + if(s_cur_plane == NULL) return 0.0f; + + int v = reinterpret_cast(inRefcon); + switch(v) + { + case gear_rat: return s_cur_plane->state->gearPosition; break; + case flap_rat: return s_cur_plane->state->flapRatio; break; + case spoi_rat: return s_cur_plane->state->spoilerRatio; break; + case sbrk_rat: return s_cur_plane->state->speedBrakeRatio; break; + case slat_rat: return s_cur_plane->state->slatRatio; break; + case swep_rat: return s_cur_plane->state->wingSweep; break; + case thrs_rat: return s_cur_plane->state->thrust; break; + case ptch_rat: return s_cur_plane->state->yokePitch; break; + case head_rat: return s_cur_plane->state->yokeHeading; break; + case roll_rat: return s_cur_plane->state->yokeRoll; break; + + case lan_lite_on: return s_cur_plane->lights.landLights; break; + case bcn_lite_on: return s_cur_plane->lights.bcnLights; break; + case str_lite_on: return s_cur_plane->lights.strbLights; break; + case nav_lite_on: return s_cur_plane->lights.navLights; break; + + default: + return 0.0f; + } +} + +int obj_get_float_array( + void * inRefcon, + float * inValues, + int inOffset, + int inCount) +{ + if(inValues == NULL) + return 1; + float rv = obj_get_float(inRefcon); + for(int i = 0; i < inCount; ++i) + inValues[i] = rv; + return inCount; +} + + + + + + + + + + +static void (*XPLMLoadObjectAsync_p)( + const char * inPath, + XPLMObjectLoaded_f inCallback, + void * inRefcon)=NULL; + +void obj_init() +{ + int sim, xplm; + XPLMHostApplicationID app; + XPLMGetVersions(&sim,&xplm,&app); + // Ben says: we need the 2.10 SDK (e.g. X-Plane 10) to have async load at all. But we need 10.30 to pick up an SDK bug + // fix where async load crashes if we queue a second load before the first completes. So for users on 10.25, they get + // pauses. + if(sim >= 10300 && xplm >= 210) + { + XPLMLoadObjectAsync_p = (void (*)(const char *, XPLMObjectLoaded_f, void *)) XPLMFindSymbol("XPLMLoadObjectAsync"); + } + + for(int i = 0; i < dref_dim; ++i) + { + XPLMRegisterDataAccessor( + dref_names[i], xplmType_Float|xplmType_FloatArray, 0, + NULL, NULL, + obj_get_float, NULL, + NULL, NULL, + NULL, NULL, + obj_get_float_array, NULL, + NULL, NULL, reinterpret_cast(i), NULL); + } +} + + + +static void draw_objects_for_mode(one_obj * who, int want_translucent) +{ + while(who) + { + obj_draw_type dt = who->model->draw_type; + if((want_translucent && dt == draw_glass) || + (!want_translucent && dt != draw_glass)) + { + for(one_inst * i = who->head; i; i = i->next) + { + s_cur_plane = i; + // set dataref ptr to light + obj sate from "one_inst". + XPLMDrawObjects(who->model->handle, 1, &i->location, 1, 0); + } + } + who = who->next; + } + s_cur_plane = NULL; +} + +void obj_loaded_cb(XPLMObjectRef obj, void * refcon) +{ + XPLMObjectRef * targ = (XPLMObjectRef *) refcon; + *targ = obj; +} + + +void obj_schedule_one_aircraft( + CSLPlane_t * model, + double x, + double y, + double z, + double pitch, + double roll, + double heading, + int full, // + xpmp_LightStatus lights, + XPLMPlaneDrawState_t * state) +{ + one_obj * iter; + + for(vector::iterator att = model->attachments.begin(); att != model->attachments.end(); ++att) + { + obj_for_acf * model = &*att; + + if(model->handle == NULL && + !model->file.empty()) + { + if(XPLMLoadObjectAsync_p) + XPLMLoadObjectAsync_p(model->file.c_str(),obj_loaded_cb,(void *) &model->handle); + else + model->handle = XPLMLoadObject(model->file.c_str()); + model->file.clear(); + } + + + for(iter = s_worklist; iter; iter = iter->next) + { + if(iter->model == model) + break; + } + if(iter == NULL) + { + iter = new one_obj; + iter->next = s_worklist; + s_worklist = iter; + iter->model = model; + iter->head = NULL; + } + + if(iter->model->handle) + { + one_inst * i = new one_inst; + i->next = iter->head; + iter->head = i; + i->lights = lights; + i->state = state; + i->location.structSize = sizeof(i->location); + i->location.x = x; + i->location.y = y; + i->location.z = z; + i->location.pitch = pitch; + i->location.roll = roll; + i->location.heading = heading; + } + } +} + +void obj_draw_solid() +{ + draw_objects_for_mode(s_worklist, false); +} + +void obj_draw_translucent() +{ + draw_objects_for_mode(s_worklist, true);\ +} + +void obj_draw_done() +{ + delete s_worklist; + s_worklist = NULL; +} diff --git a/src/XPMPMultiplayerObj8.h b/src/XPMPMultiplayerObj8.h new file mode 100644 index 000000000..c78732275 --- /dev/null +++ b/src/XPMPMultiplayerObj8.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2013, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef XPMPMultiplayerObj8_h +#define XPMPMultiplayerObj8_h + +#include "XPLMScenery.h" +#include "XPLMPlanes.h" +#include "XPMPMultiplayer.h" +#include + +/* + + OBJ8_AIRCRAFT + OBJ8 LOW_LOD NO foo.obj + OBJ8 GLASS YES bar.obj + AIRLINE DAL + ICAO B732 B733 + + */ + +enum obj_draw_type { + + draw_lights = 0, + draw_low_lod, + draw_solid, + draw_glass + +}; + +struct obj_for_acf { + + std::string file; + XPLMObjectRef handle; + obj_draw_type draw_type; + bool needs_animation; + +}; + +struct CSLPlane_t; + +void obj_init(); + +bool obj_load_one_attached_obj( + const char * file_name, + bool needs_anim, + obj_draw_type draw_type, + obj_for_acf& out_attachment); + +///// + + +void obj_schedule_one_aircraft( + CSLPlane_t * model, + double x, + double y, + double z, + double pitch, + double roll, + double heading, + int full, // + xpmp_LightStatus lights, + XPLMPlaneDrawState_t * state); + + +void obj_draw_solid(); +void obj_draw_translucent(); +void obj_draw_done(); + + + + +#endif \ No newline at end of file diff --git a/src/XPMPMultiplayerVars.h b/src/XPMPMultiplayerVars.h index dbc825e25..a7ca3c482 100644 --- a/src/XPMPMultiplayerVars.h +++ b/src/XPMPMultiplayerVars.h @@ -40,6 +40,7 @@ using namespace std; #include "XPMPMultiplayer.h" +#include "XPMPMultiplayerObj8.h" // for obj8 attachment info template inline @@ -68,6 +69,7 @@ enum { plane_Austin, plane_Obj, plane_Lights, + plane_Obj8, plane_Count }; @@ -76,16 +78,20 @@ enum { // and then implementation-specifc stuff. struct CSLPlane_t { int plane_type; // What kind are we? - string file_path; // Where do we load from + string file_path; // Where do we load from (oz and obj, debug-use-only for OBJ8) bool moving_gear; // Does gear retract? + // plane_Austin int austin_idx; + // plane_Obj int obj_idx; - // Optional Texture - int texID; - // Optional Lit Texture - int texLitID; + int texID; // can be 0 for no customization + int texLitID; // can be 0 for no customization + + // plane_Obj8 + vector attachments; + }; // These enums define the six levels of matching we might possibly diff --git a/src/XPMPPlaneRenderer.cpp b/src/XPMPPlaneRenderer.cpp index e90c994cb..1641de9af 100644 --- a/src/XPMPPlaneRenderer.cpp +++ b/src/XPMPPlaneRenderer.cpp @@ -256,7 +256,7 @@ struct PlaneToRender_t { typedef std::map RenderMap; -void XPMPDefaultPlaneRenderer(void) +void XPMPDefaultPlaneRenderer(int is_blend) { long planeCount = XPMPCountPlanes(); #if DEBUG_RENDERER @@ -454,6 +454,7 @@ void XPMPDefaultPlaneRenderer(void) vector planes_obj_lites; multimap planes_austin; multimap planes_obj; + vector planes_obj8; vector::iterator planeIter; multimap::iterator planeMapIter; @@ -490,6 +491,10 @@ void XPMPDefaultPlaneRenderer(void) planes_obj.insert(multimap::value_type(CSL_GetOGLIndex(iter->second.model), &iter->second)); planes_obj_lites.push_back(&iter->second); } + else if(iter->second.model->plane_type == plane_Obj8) + { + planes_obj8.push_back(&iter->second); + } } else { // If it's time to draw austin's planes but this one @@ -505,6 +510,7 @@ void XPMPDefaultPlaneRenderer(void) // Using the user's planes can cause the internal flight model to get f-cked up. // Using a non-loaded plane can trigger internal asserts in x-plane. if (modelCount > 1) + if(!is_blend) XPLMDrawAircraft(1, (float) iter->second.x, (float) iter->second.y, (float) iter->second.z, iter->second.pitch, iter->second.roll, iter->second.heading, @@ -527,6 +533,7 @@ void XPMPDefaultPlaneRenderer(void) // PASS 1 - draw Austin's planes. + if(!is_blend) for (planeMapIter = planes_austin.begin(); planeMapIter != planes_austin.end(); ++planeMapIter) { CSL_DrawObject( planeMapIter->second->model, @@ -549,7 +556,14 @@ void XPMPDefaultPlaneRenderer(void) } // PASS 2 - draw OBJs - + // Blend for solid OBJ7s? YES! First, in HDR mode, they DO NOT draw to the gbuffer properly - + // they splat their livery into the normal map, which is terrifying and stupid. Then they are also + // pre-lit...the net result is surprisingly not much worse than regular rendering considering how many + // bad things have happened, but for all I know we're getting NaNs somewhere. + // + // Blending isn't going to hurt things in NON-HDR because our rendering is so stupid for old objs - there's + // pretty much never translucency so we aren't going to get Z-order fails. So f--- it...always draw blend.< + if(is_blend) for (planeMapIter = planes_obj.begin(); planeMapIter != planes_obj.end(); ++planeMapIter) { CSL_DrawObject( @@ -568,8 +582,28 @@ void XPMPDefaultPlaneRenderer(void) ++gOBJPlanes; } + for(planeIter = planes_obj8.begin(); planeIter != planes_obj8.end(); ++planeIter) + { + CSL_DrawObject( (*planeIter)->model, + (*planeIter)->dist, + (*planeIter)->x, + (*planeIter)->y, + (*planeIter)->z, + (*planeIter)->pitch, + (*planeIter)->roll, + (*planeIter)->heading, + plane_Obj8, + (*planeIter)->full ? 1 : 0, + (*planeIter)->lights, + &(*planeIter)->state); + } + + if(!is_blend) + obj_draw_solid(); + // PASS 3 - draw OBJ lights. + if(is_blend) if (!planes_obj_lites.empty()) { OBJ_BeginLightDrawing(); @@ -591,7 +625,12 @@ void XPMPDefaultPlaneRenderer(void) } } + if(is_blend) + obj_draw_translucent(); + obj_draw_done(); + // PASS 4 - Labels + if(is_blend) if ( gDrawLabels ) { GLfloat vp[4];