/* * PlanetPenguin Racer * Copyright (C) 2004-2005 Volker Stroebel * * Copyright (C) 1999-2001 Jasmin F. Patry * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "course_load.h" #include "course_render.h" #include "course_quad.h" #include "game_mgr.h" #include "ppogl/base/glwrappers.h" #include "ppogl/base/os.h" #include "ppogl/images/image.h" #include "ppogl/textures.h" #include "phys_sim.h" #include "keyframe.h" #include "gl_util.h" #include "lights.h" #include "fog.h" #include "part_sys.h" #include "hud.h" #include "mirror_course.h" #include "player.h" #include "track_marks.h" #include "ppogl/base/defs.h" #include "ppogl/translation.h" #include "elements.h" #include #define MIN_ANGLE 5 #define MAX_ANGLE 80 TerrainTex terrain_texture[NUM_TERRAIN_TYPES]; unsigned int num_terrains=0; static bool course_loaded = false; static float *elevation; static float elev_scale; static ppogl::Vec2d courseDim; static ppogl::Vec2d playDim; static float course_angle; static int nx, ny; static int *terrain; static ppogl::Vec2d start_pt; static std::string courseAuthor; static std::string courseName; static int base_height_value; static std::map< std::string,ppogl::RefPtr > modelTypes; static std::map > itemTypes; ///All terrains that are used in the current course. ///The list is sorted with respect to the terrain wheights std::list usedTerrains; // Interleaved vertex, normal, and color data static GLubyte *vnc_array = NULL; float* Course::getElevData() { return elevation; } int* Course::getTerrainData() { return terrain; } float Course::getAngle() { return course_angle; } const ppogl::Vec2d& Course::getStartPt() { return start_pt; } void Course::setStartPt(const ppogl::Vec2d& p) { start_pt = p; } const std::string& Course::getAuthor() { return courseAuthor; } const std::string& Course::getName() { return courseName; } void Course::getGLArrays( GLubyte **vnc_arr ) { *vnc_arr = vnc_array; } void Course::getDimensions( float *width, float *length ) { *width = courseDim.x(); *length = courseDim.y(); } void Course::getPlayDimensions( float *width, float *length ) { *width = playDim.x(); *length = playDim.y(); } /*! Returns the base (minimum) height of the terrain at \c distance \pre A course has been loaded \arg \c distance the (non-negative) distance down the course \return Minimum height (y-coord) of terrain \author jfpatry \date Created: 2000-08-30 \date Modified: 2000-08-30 */ float Course::getTerrainBaseHeight( float distance ) { PP_REQUIRE( distance > -EPS, "distance should be positive" ); float slope = tan( ANGLES_TO_RADIANS( course_angle ) ); float base_height; /* This will need to be fixed once we add variably-sloped terrain */ base_height = -slope * distance - base_height_value / 255.0 * elev_scale; return base_height; } /*! Returns the maximum height of the terrain at \c distance \pre A course has been loaded \arg \c distance the (non-negative) distance down the course \return Maximum height (y-coord) of terrain \author jfpatry \date Created: 2000-08-30 \date Modified: 2000-08-30 */ float Course::getTerrainMaxHeight( float distance ) { return getTerrainBaseHeight( distance ) + elev_scale; } void Course::getDivisions( int *x, int *y ) { *x = nx; *y = ny; } static void reset_course() { num_terrains = 0; course_angle = 20; courseDim = ppogl::Vec2d(50,130); playDim = ppogl::Vec2d(50,130); nx = ny = -1; start_pt.x() = 0; start_pt.y() = 0; base_height_value = 127; reset_course_mirroring(); reset_lights(); fogPlane.reset(); reset_particles(); courseAuthor.erase(); courseName.erase(); if ( course_loaded == false ) return; reset_course_quadtree(); delete[] elevation; elevation=NULL; delete[] terrain; terrain=NULL; delete[] vnc_array; vnc_array=NULL; modelLocs.clear(); modelTypes.clear(); itemLocs.clear(); itemTypes.clear(); course_loaded = false; keyFrames[0].reset(); keyFrames[1].reset(); } void Course::fillGLArrays() { int x,y; ppogl::Vec3d *normals = get_course_normals(); ppogl::Vec3d nml; int idx; gl::DisableClientState(GL_VERTEX_ARRAY); gl::DisableClientState(GL_NORMAL_ARRAY); gl::DisableClientState(GL_COLOR_ARRAY); // Align vertices and normals on 16-byte intervals (Q3A does this) vnc_array = new GLubyte[STRIDE_GL_ARRAY * nx * ny]; PP_CHECK_ALLOC(vnc_array); for (x=0; x(vnc_array+idx+(i)*sizeof(GLfloat))) floatval(0) = GLfloat(x) / (nx-1.) * courseDim.x(); floatval(1) = ELEV(x,y); floatval(2) = -GLfloat(y)/ (ny-1.) * courseDim.y(); nml = normals[ x + y * nx ]; floatval(4) = nml.x(); floatval(5) = nml.y(); floatval(6) = nml.z(); floatval(7) = 1.0f; #undef floatval #define byteval(i) (*reinterpret_cast(vnc_array+idx+8*sizeof(GLfloat) +\ i*sizeof(GLubyte))) byteval(0) = 255; byteval(1) = 255; byteval(2) = 255; byteval(3) = 255; #undef byteval } } gl::EnableClientState(GL_VERTEX_ARRAY); gl::VertexPointer( 3, GL_FLOAT, STRIDE_GL_ARRAY, vnc_array ); gl::EnableClientState(GL_NORMAL_ARRAY); gl::NormalPointer( GL_FLOAT, STRIDE_GL_ARRAY, vnc_array + 4*sizeof(GLfloat) ); gl::EnableClientState(GL_COLOR_ARRAY); gl::ColorPointer( 4, GL_UNSIGNED_BYTE, STRIDE_GL_ARRAY, vnc_array + 8*sizeof(GLfloat) ); } void Course::load(const std::string& course) { reset_course(); HUD1.reset(); HUD2.reset(); std::string cwd = ppogl::os::cwd(); if(cwd.empty()){ PP_ERROR("Unable to get curent working directory"); } std::string data_dir = PPConfig.getString("data_dir"); script.doFile(data_dir+"/"+course+"/course.nut"); if(ppogl::os::chdir(cwd)==false){ PP_ERROR("Unable to change into directory: " << cwd ); } calc_normals(); fillGLArrays(); init_course_quadtree( elevation, nx, ny, courseDim.x()/(nx-1.), -courseDim.y()/(ny-1), players[0].view.pos); // init trackmarks for all players // todo: check whether we need to keep the old ones TrackMarks::init(); course_loaded = true; } static inline int intensity_to_terrain( const int intensity ) { for (unsigned int i=0; igetTop() != 1){ PP_WARNING("ppcourse.course_dim: Invalid number of arguments"); return 0; } if(vm->isArray()){ vm->pushNull(); vm->next(-2); courseDim.x() = vm->getFloat(); vm->pop(2); vm->next(-2); courseDim.y() = vm->getFloat(); vm->pop(2); if(vm->next(-2)){ playDim.x() = vm->getFloat(); vm->pop(2); vm->next(-2); playDim.y() = vm->getFloat(); vm->pop(2); }else{ playDim = courseDim; } vm->pop(); }else{ PP_WARNING("ppcourse.course_dim: Value is no array"); } return 0; } static int angle_cb(ppogl::Script *vm) { double angle; if(vm->getTop()!=1){ PP_WARNING("ppcourse.angle_cb: invalid number of arguments"); return 0; } angle = vm->getFloat(1); if(angle < MIN_ANGLE){ PP_WARNING("course angle is too small. Setting to " << MIN_ANGLE); angle = MIN_ANGLE; } if(MAX_ANGLE < angle){ PP_WARNING("course angle is too large. Setting to " << MAX_ANGLE); angle = MAX_ANGLE; } course_angle = angle; return 0; } static int elev_cb(ppogl::Script *vm) { ppogl::Image *elev_img; float slope; int x,y; int pad; if(vm->getTop() != 1){ PP_WARNING("ppcourse.elev: Invalid number of arguments"); return 0; } if(course_loaded){ PP_WARNING("Ignoring ppcourse.elev: course already loaded"); return 0; } std::string filename = vm->getString(1); elev_img = ppogl::Image::readFile(filename); if ( elev_img == NULL ) { PP_WARNING( "ppcourse.elev: couldn't load " << filename); return 0; } nx = elev_img->width; ny = elev_img->height; elevation = new float[nx*ny]; PP_CHECK_ALLOC(elevation); slope = tan( ANGLES_TO_RADIANS( course_angle ) ); pad = 0; /* RGBA images rows are aligned on 4-byte boundaries */ for (y=0; ydata[ (x + nx * y) * elev_img->depth + pad ] - base_height_value ) / 255.0 ) * elev_scale - double(ny-1.-y)/ny * courseDim.y() * slope; } //pad += (nx*elev_img->depth) % 4; } delete elev_img; return 0; } static bool sort_terrain(const int x, const int y) { if(terrain_texture[x].wheight < terrain_texture[y].wheight){ return true; }else{ return false; } } static int terrain_cb(ppogl::Script *vm) { ppogl::Image *terrain_img; int x,y; int pad; int idx; int terrain_value; int image_pointer; if(vm->getTop()!=1){ PP_WARNING("ppcourse.load_terrain: Invalid number of arguments"); return 0; } std::string filename = vm->getString(1); terrain_img = ppogl::Image::readFile(filename); if(terrain_img == NULL){ PP_WARNING("ppcourse.load_terrain: couldn't load " << filename); return 0; } if ( nx != terrain_img->width || ny != terrain_img->height ) { PP_WARNING("ppcourse.load_terrain: terrain bitmap must have same " "dimensions as elevation bitmap"); return 0; } terrain = new int[nx*ny]; PP_CHECK_ALLOC(terrain); pad = 0; for (y=0; ydepth+pad; terrain_value=terrain_img->data[image_pointer] + (terrain_img->data[image_pointer+1] << 8)+ (terrain_img->data[image_pointer+2] << 16); terrain[idx] = intensity_to_terrain(terrain_value); } } delete terrain_img; //build sorted list with used terrains for quadtree usedTerrains.clear(); for (unsigned int i=0; i0){ usedTerrains.push_back(i); } } usedTerrains.sort(sort_terrain); return 0; } static int terrain_tex_cb(ppogl::Script *vm) { if(num_terrains>=NUM_TERRAIN_TYPES){ PP_WARNING("pptheme.terrain_tex: Max number of terrains reached"); return 0; } // fill in values not specified with defaults terrain_texture[num_terrains].type=1; terrain_texture[num_terrains].value=0; terrain_texture[num_terrains].friction=0.5; terrain_texture[num_terrains].compression=0.1; terrain_texture[num_terrains].soundactive=false; terrain_texture[num_terrains].wheight=150; terrain_texture[num_terrains].count=0; std::string name = vm->getStringFromTable("name"); std::string filename = vm->getStringFromTable("filename"); if(name.empty() || filename.empty()){ PP_WARNING("pptheme.terrain_tex: Please specify name and texture"); return 0; } ppogl::TextureRef texture = ppogl::TextureMgr::getInstance().load(name, filename); terrain_texture[num_terrains].texture = texture; if(!terrain_texture[num_terrains].texture){ PP_WARNING("pptheme.terrain_tex: Unable to load texture " << filename << " for terrain " << name); return 0; } if(vm->isKeyInTable("color")){ vm->pushString("color"); if(vm->get() && vm->isArray()){ //color value int temp_value=0; vm->pushNull(); for(int i=0; i<3; i++){ vm->next(-2); temp_value += (vm->getInt() << (8*i)); vm->pop(2); } terrain_texture[num_terrains].value=temp_value; vm->pop(2); }else{ PP_WARNING("pptheme.terrain_tex: Invalid color in terrain type " << name); } }else{ PP_WARNING("Terrain type " << name << " has no color"); } if(vm->isKeyInTable("friction")){ terrain_texture[num_terrains].friction=vm->getFloatFromTable("friction"); } if(vm->isKeyInTable("compression")){ terrain_texture[num_terrains].compression=vm->getFloatFromTable("compression"); } if(vm->isKeyInTable("wheight")){ terrain_texture[num_terrains].wheight=vm->getIntFromTable("wheight"); } if(vm->isKeyInTable("sound")){ terrain_texture[num_terrains].sound=vm->getStringFromTable("sound"); } if(vm->isKeyInTable("particle")){ terrain_texture[num_terrains].particles = ppogl::TextureMgr::getInstance().get( vm->getStringFromTable("particle")); } if(vm->isKeyInTable("track_head")){ terrain_texture[num_terrains].trackmark.head = ppogl::TextureMgr::getInstance().get( vm->getStringFromTable("track_head")); } if(vm->isKeyInTable("track_mark")){ terrain_texture[num_terrains].trackmark.mark = ppogl::TextureMgr::getInstance().get( vm->getStringFromTable("track_mark")); } if(vm->isKeyInTable("track_tail")){ terrain_texture[num_terrains].trackmark.tail = ppogl::TextureMgr::getInstance().get( vm->getStringFromTable("track_tail")); } if(vm->isKeyInTable("envmap_texture")){ terrain_texture[num_terrains].envmap = ppogl::TextureMgr::getInstance().get( vm->getStringFromTable("envmap_texture")); } num_terrains++; return 0; } static int start_pt_cb(ppogl::Script *vm) { double xcd =0; double ycd =0; if(vm->getTop() != 1){ PP_WARNING("ppcourse.start_pt: Invalid number of arguments"); return 0; } if(vm->isArray()){ vm->pushNull(); vm->next(-2); xcd = vm->getFloat(); vm->pop(2); vm->next(-2); ycd = vm->getFloat(); vm->pop(2); vm->pop(); }else{ PP_WARNING("ppcourse.start_pt: Value is no array"); } if(!( xcd > 0 && xcd < courseDim.x() )){ PP_WARNING("ppcourse.start_pt: x coordinate out of bounds, " "using 0"); xcd = 0; } if (!( ycd > 0 && ycd < courseDim.y() )){ PP_WARNING("ppcourse.start_pt: y coordinate out of bounds, " "using 0"); ycd = 0; } start_pt.x() = xcd; start_pt.y() = -ycd; return 0; } static int elev_scale_cb(ppogl::Script *vm) { double scale; if(vm->getTop() != 1){ PP_WARNING("ppcourse.elev_scale: invalid number of arguments"); return 0; } scale = vm->getFloat(1); if(scale <= 0){ PP_WARNING("ppcourse.elev_scale: scale must be positive"); return 0; } elev_scale = scale; return 0; } static int elements_cb(ppogl::Script *vm) { if(vm->getTop()!=1){ PP_WARNING("ppcourse.elements: Invalid number of arguments"); return 0; } ppogl::Image *elementsImg; std::string filename = vm->getString(1); if(filename.empty()){ // no elements image specified return 0; } elementsImg = ppogl::Image::readFile(filename); if(elementsImg->data == NULL){ PP_WARNING( "ppcourse.load_elements: couldn't load image: " << filename); return 0; } ppogl::Image::iterator it; for(it=elementsImg->begin();it!=elementsImg->end();it++){ if( !(*it).compareRGB(ppogl::Color4c::black) ){ // the pixel is not black, // check for an element type with this color value bool found=false; std::map >::iterator modelit; for(modelit=modelTypes.begin();modelit!=modelTypes.end();modelit++){ if( (*modelit).second->color.compareRGB(*it) ){ // yes, that's the right model double x = (elementsImg->width-it.getX())/double(elementsImg->width-1.0)*courseDim.x(); double z =-(elementsImg->height-it.getY())/double(elementsImg->height-1.0)*courseDim.y(); double y = find_y_coord(x,z) + (*modelit).second->height; Model model((*modelit).second, ppogl::Vec3d(x,y,z)); modelLocs.push_back(model); found=true; break; } } if(found)continue; std::map >::iterator itemit; for(itemit=itemTypes.begin();itemit!=itemTypes.end();itemit++){ if( (*itemit).second->color.compareRGB(*it) ){ // yes, that's the right item double x = (elementsImg->width-it.getX())/double(elementsImg->width-1.0)*courseDim.x(); double z =-(elementsImg->height-it.getY())/double(elementsImg->height-1.0)*courseDim.y(); double y = find_y_coord(x,z) + (*itemit).second->above_ground; if( (*itemit).second->reset_point ){ resetLocs.push_back(ppogl::Vec2d(x,z)); found=true; break; }else{ Item item((*itemit).second, ppogl::Vec3d(x,y,z)); itemLocs.push_back(item); found=true; break; } } } } } return 0; } static int model_spec_cb(ppogl::Script *vm) { if( !vm->isKeyInTable("name") || !vm->isKeyInTable("file")) { PP_WARNING("pptheme.model: Please specify name and file"); return 0; } ppogl::RefPtr model = new ModelType; std::string name = vm->getStringFromTable("name"); model->setModel(ppogl::ModelRef( new ppogl::Model(vm->getStringFromTable("file")) )); if(vm->isKeyInTable("diameter")){ model->diameter = vm->getFloatFromTable("diameter"); } if(vm->isKeyInTable("height")){ model->height = vm->getFloatFromTable("height"); } if(vm->isKeyInTable("color")){ vm->pushString("color"); if(vm->get() && vm->isArray()){ vm->pushNull(); for(int i=0; i<3; i++){ vm->next(-2); model->color.values[i] = vm->getInt(); vm->pop(2); } vm->pop(2); }else{ PP_WARNING("pptheme.model: Invalid color in model type " << name); } }else{ PP_WARNING("pptheme.model: No color specified for model"); } // attach model to map // an existing model with the same name will be replaced modelTypes[name]=model; return 0; } static int reset_point_cb(ppogl::Script *vm) { if(!vm->isArray(1)){ PP_WARNING("pptheme.reset_point: Invalid color table"); return 0; } ppogl::RefPtr item = new ItemType; vm->pushNull(); for(int i=0; i<3; i++){ vm->next(1); item->color.values[i]=vm->getInt(); vm->pop(2); } vm->pop(); item->reset_point = true; item->type = ItemType::UNCOLLECTABLE; itemTypes["reset_point"]=item; return 0; } static int item_spec_cb(ppogl::Script *vm) { if( !vm->isKeyInTable("name") || !vm->isKeyInTable("element_type") || !vm->isKeyInTable("texture")) { PP_WARNING("pptheme.item: Please specify name, element_type and texture"); return 0; } std::string name = vm->getStringFromTable("name"); std::string type = vm->getStringFromTable("element_type"); std::string texture = vm->getStringFromTable("texture"); ppogl::RefPtr item = new ItemType; item->texture = ppogl::TextureMgr::getInstance().get(texture); if(!item->texture){ PP_WARNING("pptheme.item: Unable to get texture for item " << name << ": " << texture); return 0; } if(type=="herring"){ item->type=ItemType::HERRING; }else if(type=="life"){ item->type=ItemType::LIFE; } if(vm->isKeyInTable("diameter")){ item->diam = vm->getFloatFromTable("diameter"); } if(vm->isKeyInTable("height")){ item->height = vm->getFloatFromTable("height"); } if(vm->isKeyInTable("above_ground")){ item->above_ground = vm->getFloatFromTable("above_ground"); } if(vm->isKeyInTable("score")){ item->score = vm->getIntFromTable("score"); } if(vm->isKeyInTable("color")){ vm->pushString("color"); if(vm->get() && vm->isArray()){ vm->pushNull(); for(int i=0; i<3; i++){ vm->next(-2); item->color.values[i] = vm->getInt(); vm->pop(2); } vm->pop(2); }else{ PP_WARNING("pptheme.item: Invalid color in item type " << name); } }else{ PP_WARNING("pptheme.item: No color specified for item"); } if(vm->isKeyInTable("normal")){ vm->pushString("normal"); if(vm->get() && vm->isArray()){ vm->pushNull(); for(int i=0; i<3; i++){ vm->next(-2); item->normal.values[i] = vm->getFloat(); vm->pop(2); } vm->pop(2); item->use_normal=true; }else{ PP_WARNING("pptheme.item: Invalid normal in item type " << name); } vm->pop(2); } itemTypes[name]=item; return 0; } static int wind_velocity_cb(ppogl::Script *vm) { if(vm->getTop()>2){ PP_WARNING("pptheme.wind_velocity: Invalid number of arguments"); return 0; } ppogl::Vec3d velocity; double scale = 1.0; if(vm->isArray(1)){ vm->pushNull(); for(int i=0; i<3; i++){ vm->next(1); velocity.values[i]=vm->getFloat(); vm->pop(2); } }else{ PP_WARNING("pptheme.wind_velocity: Invalid direction"); return 0; } vm->pop(); if(vm->getTop()==2){ scale = vm->getFloat(2); } set_wind_velocity(velocity,scale); return 0; } static int hud_cb(ppogl::Script *vm) { if(vm->getTop() != 1){ PP_WARNING("pptheme.hud: Invalid number of arguments"); return 0; } int element_num=-1; HUD::Element element; int hud = int(vm->getFloatFromTable("hud")); if(!vm->isKeyInTable("element_type")){ PP_WARNING("pptheme.hud: No element type specified"); return 0; } std::string type = vm->getStringFromTable("element_type"); if(type=="text"){ element.type=0; }else if(type=="fsb"){ element.type=1; }else if(type=="herring"){ element.type=2; }else if(type=="image"){ element.type=3; }else if(type=="time"){ element.type=4; }else if(type=="speed"){ element.type=5; }else if(type=="gauge"){ element.type=6; }else if(type=="energybar"){ element.type=7; }else if(type=="speedbar"){ element.type=8; }else if(type=="percentage"){ element.type=9; }else if(type=="percentagebar"){ element.type=10; }else{ PP_WARNING("pptheme.hud: Unknown type: " << type); return 0; } if(vm->isKeyInTable("position")){ vm->pushString("position"); if(vm->get() && vm->isArray()){ // position array vm->pushNull(); vm->next(-2); element.x = vm->getInt(); vm->pop(2); vm->next(-2); element.y = vm->getInt(); vm->pop(2); vm->pop(2); //the table }else{ PP_WARNING("pptheme.hud: Invalid position"); } } //texture if(vm->isKeyInTable("texture")){ std::string texture = vm->getStringFromTable("texture"); element.texture = ppogl::TextureMgr::getInstance().get(texture); if(!element.texture){ PP_WARNING("pptheme.hud: Unable to get texture: " << texture); } } // width if(vm->isKeyInTable("width")){ element.width = vm->getIntFromTable("width"); } // height if(vm->isKeyInTable("height")){ element.height = vm->getIntFromTable("height"); } // size if(vm->isKeyInTable("size")){ element.size = vm->getIntFromTable("size"); } // string if(vm->isKeyInTable("string")){ element.string = _(vm->getStringFromTable("string")); } // font if(vm->isKeyInTable("font")){ std::string font = vm->getStringFromTable("font"); element.font = ppogl::FontMgr::getInstance().get(font); if(!element.font){ PP_WARNING("pptheme.hud: Unable to get font: " << font); }else{ element.height = int(element.font->ascender()); } } // angle if(vm->isKeyInTable("angle")){ element.angle = vm->getIntFromTable("angle"); } //precalculate unicode string and width of the font if(element.type==0 && element.font && !element.string.empty()){ ppogl::Font::utf8ToUnicode(element.u_string,element.string); element.width = int(element.font->advance(element.u_string)); } if(hud!=1){ PP_WARNING("pptheme.hud: Invalid hud " << hud << " is not supported"); }else{ if(element_num==-1){ HUD1.add(element); //only for testing purpose HUD2.add(element); }else{ HUD1.update(element_num,element); //only for testing purpose HUD2.update(element_num,element); } } return 0; } static int get_condition_cb(ppogl::Script *vm) { switch(GameMgr::getInstance().getCurrentRace().condition) { case RACE_CONDITIONS_CLOUDY: vm->pushString("cloudy"); break; case RACE_CONDITIONS_NIGHT: vm->pushString("night"); break; case RACE_CONDITIONS_EVENING: vm->pushString("evening"); break; default: vm->pushString("sunny"); } return 1; } static int base_height_value_cb(ppogl::Script *vm) { if(vm->getTop()!=1){ PP_WARNING("ppcourse.base_height_value: Invalid number of arguments"); } int value = vm->getInt(1); if(value<0) value=0; else if(value>255) value=255; base_height_value = value; return 0; } static int add_model_cb(ppogl::Script *vm) { if(!vm->isTable()){ PP_WARNING("ppcourse.add_model: Arguments needs to be a table"); return 0; } std::string name = vm->getStringFromTable("name"); if(name.empty()){ PP_WARNING("ppcourse.add_model: No name given for model"); } ppogl::Vec3d position; if(vm->isKeyInTable("position")){ vm->pushString("position"); if(vm->get() && vm->isArray()){ // position array vm->pushNull(); vm->next(-2); position.x() = vm->getFloat(); vm->pop(2); vm->next(-2); position.z() = (-1)*vm->getFloat(); vm->pop(2); vm->pop(2); }else{ PP_WARNING("ppcourse.add_model: Invalid position"); return 0; } } std::map >::iterator it; if((it=modelTypes.find(name))==modelTypes.end()){ PP_WARNING("ppcourse.add_item: Unable to find item: " << name); return 0; } double aboveGround = (*it).second->height; if(vm->isKeyInTable("above_ground")){ aboveGround += vm->getFloatFromTable("above_ground"); } position.y() = find_y_coord(position.x(),position.z()) + aboveGround; Model model((*it).second, position); modelLocs.push_back(model); return 0; } static int add_item_cb(ppogl::Script *vm) { if(!vm->isTable()){ PP_WARNING("ppcourse.add_item: Arguments needs to be a table"); return 0; } std::string name = vm->getStringFromTable("name"); if(name.empty()){ PP_WARNING("ppcourse.add_item: No name given for item"); } ppogl::Vec3d position; if(vm->isKeyInTable("position")){ vm->pushString("position"); if(vm->get() && vm->isArray()){ // position array vm->pushNull(); vm->next(-2); position.x() = vm->getFloat(); vm->pop(2); vm->next(-2); position.z() = (-1)*vm->getFloat(); vm->pop(2); vm->pop(2); }else{ PP_WARNING("ppcourse.add_item: Invalid position"); return 0; } } std::map >::iterator it; if((it=itemTypes.find(name))==itemTypes.end()){ PP_WARNING("ppcourse.add_item: Unable to find item: " << name); return 0; } double aboveGround = (*it).second->above_ground; if(vm->isKeyInTable("above_ground")){ aboveGround = vm->getFloatFromTable("above_ground"); } position.y() = find_y_coord(position.x(),position.z()) + aboveGround; Item item((*it).second, position); if(vm->isKeyInTable("normal")){ vm->pushString("normal"); if(vm->get() && vm->isArray()){ ppogl::Vec3d normal; vm->pushNull(); for(int i=0; i<3; i++){ vm->next(-2); normal.values[i] = vm->getFloat(); vm->pop(2); } vm->pop(2); item.setNormal(normal); } } if(vm->isKeyInTable("diameter")){ item.setDiameter(vm->getFloatFromTable("diameter")); } if(vm->isKeyInTable("height")){ item.setHeight(vm->getFloatFromTable("height")); } itemLocs.push_back(item); return 0; } static int add_reset_point_cb(ppogl::Script *vm) { ppogl::Vec2d position; if(vm->isArray()){ // position array vm->pushNull(); vm->next(-2); position.x() = vm->getFloat(); vm->pop(2); vm->next(-2); position.x() = (-1)*vm->getFloat(); vm->pop(2); vm->pop(2); }else{ PP_WARNING("ppcourse.add_reset_point: Invalid position"); return 0; } resetLocs.push_back(position); return 0; } static const struct ppogl::Script::Lib ppcourselib[]={ {"course_dim", course_dim_cb}, {"start_pt", start_pt_cb}, {"angle", angle_cb}, {"elev_scale", elev_scale_cb}, {"elev", elev_cb}, {"load_terrain", terrain_cb}, {"load_elements", elements_cb}, {"get_condition", get_condition_cb}, {"base_height_value", base_height_value_cb}, {"add_model", add_model_cb}, {"add_item", add_item_cb}, {"add_reset_point", add_reset_point_cb}, {NULL, NULL} }; static const struct ppogl::Script::Lib ppthemelib[]={ {"terrain_tex", terrain_tex_cb}, {"hud", hud_cb}, {"wind_velocity", wind_velocity_cb}, {"reset_point", reset_point_cb}, {"item", item_spec_cb}, {"model", model_spec_cb}, {NULL, NULL} }; void Course::registerCallbacks() { script.registerLib("ppcourse", ppcourselib); script.registerLib("pptheme", ppthemelib); }