mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-22 10:22:52 +01:00
Merge pull request #241 from danhedron/new-object-data
Correct object data storage
This commit is contained in:
commit
02efff6f8f
@ -36,8 +36,8 @@ set(RWENGINE_SOURCES
|
|||||||
src/data/GameTexts.cpp
|
src/data/GameTexts.cpp
|
||||||
src/data/GameTexts.hpp
|
src/data/GameTexts.hpp
|
||||||
src/data/InstanceData.hpp
|
src/data/InstanceData.hpp
|
||||||
src/data/ObjectData.cpp
|
src/data/ModelData.cpp
|
||||||
src/data/ObjectData.hpp
|
src/data/ModelData.hpp
|
||||||
src/data/PathData.hpp
|
src/data/PathData.hpp
|
||||||
src/data/Skeleton.cpp
|
src/data/Skeleton.cpp
|
||||||
src/data/Skeleton.hpp
|
src/data/Skeleton.hpp
|
||||||
@ -61,7 +61,6 @@ set(RWENGINE_SOURCES
|
|||||||
src/items/InventoryItem.hpp
|
src/items/InventoryItem.hpp
|
||||||
src/items/WeaponItem.cpp
|
src/items/WeaponItem.cpp
|
||||||
src/items/WeaponItem.hpp
|
src/items/WeaponItem.hpp
|
||||||
src/loaders/BackgroundLoader.hpp
|
|
||||||
src/loaders/DataLoader.cpp
|
src/loaders/DataLoader.cpp
|
||||||
src/loaders/DataLoader.hpp
|
src/loaders/DataLoader.hpp
|
||||||
src/loaders/GenericDATLoader.cpp
|
src/loaders/GenericDATLoader.cpp
|
||||||
|
@ -179,7 +179,7 @@ bool Activities::EnterVehicle::update(CharacterObject *character,
|
|||||||
RW_UNUSED(controller);
|
RW_UNUSED(controller);
|
||||||
|
|
||||||
// Boats don't have any kind of entry animation unless you're onboard.
|
// Boats don't have any kind of entry animation unless you're onboard.
|
||||||
if (vehicle->vehicle->type == VehicleData::BOAT) {
|
if (vehicle->getVehicle()->vehicletype_ == VehicleModelInfo::BOAT) {
|
||||||
character->enterVehicle(vehicle, seat);
|
character->enterVehicle(vehicle, seat);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -344,7 +344,7 @@ bool Activities::ExitVehicle::update(CharacterObject *character,
|
|||||||
anm_exit = character->animations.car_getout_rhs;
|
anm_exit = character->animations.car_getout_rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vehicle->vehicle->type == VehicleData::BOAT) {
|
if (vehicle->getVehicle()->vehicletype_ == VehicleModelInfo::BOAT) {
|
||||||
auto ppos = character->getPosition();
|
auto ppos = character->getPosition();
|
||||||
character->enterVehicle(nullptr, seat);
|
character->enterVehicle(nullptr, seat);
|
||||||
character->setPosition(ppos);
|
character->setPosition(ppos);
|
||||||
|
1
rwengine/src/data/ModelData.cpp
Normal file
1
rwengine/src/data/ModelData.cpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "data/ModelData.hpp"
|
428
rwengine/src/data/ModelData.hpp
Normal file
428
rwengine/src/data/ModelData.hpp
Normal file
@ -0,0 +1,428 @@
|
|||||||
|
#ifndef RWENGINE_MODELDATA_HPP
|
||||||
|
#define RWENGINE_MODELDATA_HPP
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <data/Model.hpp>
|
||||||
|
#include <data/PathData.hpp>
|
||||||
|
#include <rw/defines.hpp>
|
||||||
|
#ifdef RW_WINDOWS
|
||||||
|
#include <rw_mingw.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16-bit model ID identifier (from .ide)
|
||||||
|
*/
|
||||||
|
using ModelID = uint16_t;
|
||||||
|
|
||||||
|
enum class ModelDataType {
|
||||||
|
SimpleInfo = 1,
|
||||||
|
/** Unknown */
|
||||||
|
MLoModelInfo = 2,
|
||||||
|
/** Currently unused; data in SimpleInfo instead */
|
||||||
|
TimeModelInfo = 3,
|
||||||
|
ClumpInfo = 4,
|
||||||
|
VehicleInfo = 5,
|
||||||
|
PedInfo = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base type for all model information
|
||||||
|
*
|
||||||
|
* @todo reference counting
|
||||||
|
* @todo store collision model
|
||||||
|
*/
|
||||||
|
class BaseModelInfo {
|
||||||
|
public:
|
||||||
|
std::string name;
|
||||||
|
std::string textureslot;
|
||||||
|
|
||||||
|
BaseModelInfo(ModelDataType type) : type_(type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~BaseModelInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelID id() const {
|
||||||
|
return modelid_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setModelID(ModelID id) {
|
||||||
|
modelid_ = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelDataType type() const {
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addReference() {
|
||||||
|
refcount_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeReference() {
|
||||||
|
refcount_--;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getReferenceCount() const {
|
||||||
|
return refcount_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @todo replace with proper streaming implementation
|
||||||
|
virtual bool isLoaded() const = 0;
|
||||||
|
|
||||||
|
virtual void unload() = 0;
|
||||||
|
|
||||||
|
static std::string getTypeName(ModelDataType type) {
|
||||||
|
switch (type) {
|
||||||
|
case ModelDataType::SimpleInfo:
|
||||||
|
return "Simple";
|
||||||
|
case ModelDataType::VehicleInfo:
|
||||||
|
return "Vehicle";
|
||||||
|
case ModelDataType::PedInfo:
|
||||||
|
return "Pedestrian";
|
||||||
|
case ModelDataType::ClumpInfo:
|
||||||
|
return "Cutscene";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ModelID modelid_ = 0;
|
||||||
|
ModelDataType type_;
|
||||||
|
int refcount_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model data for simple types
|
||||||
|
*
|
||||||
|
* @todo replace Model* with librw types
|
||||||
|
*/
|
||||||
|
class SimpleModelInfo : public BaseModelInfo {
|
||||||
|
public:
|
||||||
|
static constexpr ModelDataType kType = ModelDataType::SimpleInfo;
|
||||||
|
|
||||||
|
/// @todo Use TimeModelInfo instead of hacking this in here
|
||||||
|
int timeOn = 0;
|
||||||
|
int timeOff = 24;
|
||||||
|
int flags;
|
||||||
|
/// @todo Remove this?
|
||||||
|
bool LOD = false;
|
||||||
|
/// Information loaded from PATH sections
|
||||||
|
/// @todo remove this from here too :)
|
||||||
|
std::vector<PathData> paths;
|
||||||
|
|
||||||
|
SimpleModelInfo() : BaseModelInfo(kType) {
|
||||||
|
}
|
||||||
|
SimpleModelInfo(ModelDataType type) : BaseModelInfo(type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @todo change with librw
|
||||||
|
void setAtomic(Model* model, int n, ModelFrame* atomic) {
|
||||||
|
model_ = model;
|
||||||
|
atomics_[n] = atomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @todo remove this
|
||||||
|
Model* getModel() const {
|
||||||
|
return model_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelFrame* getAtomic(int n) const {
|
||||||
|
return atomics_[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLodDistance(int n, float d) {
|
||||||
|
RW_CHECK(n < 3, "Lod Index out of range");
|
||||||
|
loddistances_[n] = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
float getLodDistance(int n) {
|
||||||
|
RW_CHECK(n < 3, "Lod Index out of range");
|
||||||
|
return loddistances_[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNumAtomics(int num) {
|
||||||
|
numatomics_ = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNumAtomics() const {
|
||||||
|
return numatomics_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isLoaded() const override {
|
||||||
|
return model_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unload() override {
|
||||||
|
delete model_;
|
||||||
|
model_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/// Cull model if player doesn't look at it. Ignored in GTA 3.
|
||||||
|
NORMAL_CULL = 1,
|
||||||
|
/// Do not fade the object when it is being
|
||||||
|
/// loaded into or out of view.
|
||||||
|
DO_NOT_FADE = 1 << 1,
|
||||||
|
/// Model is transparent. Render this object after
|
||||||
|
/// all opaque objects, allowing transparencies of
|
||||||
|
/// other objects to be visible through this
|
||||||
|
/// object.
|
||||||
|
DRAW_LAST = 1 << 2,
|
||||||
|
/// Render with additive blending. Previous flag
|
||||||
|
/// must be enabled too.
|
||||||
|
ADDITIVE = 1 << 3,
|
||||||
|
/// Model is a tunnel, i.e. set the object as
|
||||||
|
/// invisible unless the player enters cull zone
|
||||||
|
/// flag 128. This flag works only with static
|
||||||
|
/// models.
|
||||||
|
IS_SUBWAY = 1 << 4,
|
||||||
|
/// Don't use static lighting, we want
|
||||||
|
/// dynamic if it's possible.
|
||||||
|
IGNORE_LIGHTING = 1 << 5,
|
||||||
|
/// Model is a shadow. Disable writing to z-buffer when
|
||||||
|
/// rendering it, allowing transparencies of other objects,
|
||||||
|
/// shadows, and lights to be visible through this object.
|
||||||
|
/// (Not implemented in the PS2 version)
|
||||||
|
NO_ZBUFFER_WRITE = 1 << 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
Model* model_ = nullptr;
|
||||||
|
ModelFrame* atomics_[3] = {};
|
||||||
|
float loddistances_[3] = {};
|
||||||
|
uint8_t numatomics_ = 0;
|
||||||
|
uint8_t alpha_ = 0; /// @todo ask aap why
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo this
|
||||||
|
*/
|
||||||
|
class TimeModelInfo : public SimpleModelInfo {
|
||||||
|
TimeModelInfo() : SimpleModelInfo(ModelDataType::TimeModelInfo) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo document me
|
||||||
|
*/
|
||||||
|
class ClumpModelInfo : public BaseModelInfo {
|
||||||
|
public:
|
||||||
|
static constexpr ModelDataType kType = ModelDataType::ClumpInfo;
|
||||||
|
|
||||||
|
ClumpModelInfo() : BaseModelInfo(kType) {
|
||||||
|
}
|
||||||
|
ClumpModelInfo(ModelDataType type) : BaseModelInfo(type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void setModel(Model* model) {
|
||||||
|
model_ = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
Model* getModel() const {
|
||||||
|
return model_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isLoaded() const override {
|
||||||
|
return model_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unload() override {
|
||||||
|
delete model_;
|
||||||
|
model_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Model* model_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for a vehicle model type
|
||||||
|
*/
|
||||||
|
class VehicleModelInfo : public ClumpModelInfo {
|
||||||
|
public:
|
||||||
|
static constexpr ModelDataType kType = ModelDataType::VehicleInfo;
|
||||||
|
|
||||||
|
VehicleModelInfo() : ClumpModelInfo(kType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
enum VehicleClass {
|
||||||
|
IGNORE = 0,
|
||||||
|
NORMAL = 1,
|
||||||
|
POORFAMILY = 1 << 1,
|
||||||
|
RICHFAMILY = 1 << 2,
|
||||||
|
EXECUTIVE = 1 << 3,
|
||||||
|
WORKER = 1 << 4,
|
||||||
|
BIG = 1 << 5,
|
||||||
|
TAXI = 1 << 6,
|
||||||
|
MOPED = 1 << 7,
|
||||||
|
MOTORBIKE = 1 << 8,
|
||||||
|
LEISUREBOAT = 1 << 9,
|
||||||
|
WORKERBOAT = 1 << 10,
|
||||||
|
BICYCLE = 1 << 11,
|
||||||
|
ONFOOT = 1 << 12,
|
||||||
|
/// @todo verify that this is the correct bit
|
||||||
|
SPECIAL = 1 << 13,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum VehicleType {
|
||||||
|
CAR,
|
||||||
|
BOAT,
|
||||||
|
TRAIN,
|
||||||
|
PLANE,
|
||||||
|
HELI,
|
||||||
|
};
|
||||||
|
|
||||||
|
VehicleType vehicletype_;
|
||||||
|
ModelID wheelmodel_;
|
||||||
|
float wheelscale_;
|
||||||
|
int numdoors_;
|
||||||
|
std::string handling_;
|
||||||
|
VehicleClass vehicleclass_;
|
||||||
|
int frequency_;
|
||||||
|
int level_;
|
||||||
|
int componentrules_;
|
||||||
|
std::string vehiclename_;
|
||||||
|
|
||||||
|
static VehicleType findVehicleType(const std::string& name) {
|
||||||
|
static const std::unordered_map<std::string, VehicleType> vehicleTypes{
|
||||||
|
{"car", CAR},
|
||||||
|
{"boat", BOAT},
|
||||||
|
{"train", TRAIN},
|
||||||
|
{"plane", PLANE},
|
||||||
|
{"heli", HELI}};
|
||||||
|
return vehicleTypes.at(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VehicleClass findVehicleClass(const std::string& name) {
|
||||||
|
static const std::unordered_map<std::string, VehicleClass> classTypes{
|
||||||
|
// III, VC, SA
|
||||||
|
{"ignore", IGNORE},
|
||||||
|
{"normal", NORMAL},
|
||||||
|
{"poorfamily", POORFAMILY},
|
||||||
|
{"richfamily", RICHFAMILY},
|
||||||
|
{"executive", EXECUTIVE},
|
||||||
|
{"worker", WORKER},
|
||||||
|
{"big", BIG},
|
||||||
|
{"taxi", TAXI},
|
||||||
|
{"special", SPECIAL},
|
||||||
|
// VC, SA
|
||||||
|
{"moped", MOPED},
|
||||||
|
{"motorbike", MOTORBIKE},
|
||||||
|
{"leisureboat", LEISUREBOAT},
|
||||||
|
{"workerboat", WORKERBOAT},
|
||||||
|
{"bicycle", BICYCLE},
|
||||||
|
{"onfoot", ONFOOT},
|
||||||
|
};
|
||||||
|
return classTypes.at(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PedModelInfo : public ClumpModelInfo {
|
||||||
|
public:
|
||||||
|
static constexpr ModelDataType kType = ModelDataType::PedInfo;
|
||||||
|
|
||||||
|
PedModelInfo() : ClumpModelInfo(kType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PedType {
|
||||||
|
// III
|
||||||
|
PLAYER1 = 0,
|
||||||
|
PLAYER2,
|
||||||
|
PLAYER3,
|
||||||
|
PLAYER_4,
|
||||||
|
CIVMALE,
|
||||||
|
CIVFEMALE,
|
||||||
|
COP,
|
||||||
|
GANG1,
|
||||||
|
GANG2,
|
||||||
|
GANG3,
|
||||||
|
GANG4,
|
||||||
|
GANG5,
|
||||||
|
GANG6,
|
||||||
|
GANG7,
|
||||||
|
GANG8,
|
||||||
|
GANG9,
|
||||||
|
EMERGENCY,
|
||||||
|
FIREMAN,
|
||||||
|
CRIMINAL,
|
||||||
|
_UNNAMED,
|
||||||
|
PROSTITUTE,
|
||||||
|
SPECIAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
PedType pedtype_ = PLAYER1;
|
||||||
|
/// @todo this should be an index
|
||||||
|
std::string behaviour_;
|
||||||
|
/// @todo this should be an index
|
||||||
|
std::string animgroup_;
|
||||||
|
/// The mask of vehicle classes this ped can drive
|
||||||
|
int carsmask_ = 0;
|
||||||
|
|
||||||
|
static PedType findPedType(const std::string& name) {
|
||||||
|
static const std::unordered_map<std::string, PedType> pedTypes{
|
||||||
|
// III
|
||||||
|
{"PLAYER1", PLAYER1},
|
||||||
|
{"PLAYER2", PLAYER2},
|
||||||
|
{"PLAYER3", PLAYER3},
|
||||||
|
{"PLAYER_4", PLAYER_4},
|
||||||
|
{"CIVMALE", CIVMALE},
|
||||||
|
{"CIVFEMALE", CIVFEMALE},
|
||||||
|
{"COP", COP},
|
||||||
|
{"GANG1", GANG1},
|
||||||
|
{"GANG2", GANG2},
|
||||||
|
{"GANG3", GANG3},
|
||||||
|
{"GANG4", GANG4},
|
||||||
|
{"GANG5", GANG5},
|
||||||
|
{"GANG6", GANG6},
|
||||||
|
{"GANG7", GANG7},
|
||||||
|
{"GANG8", GANG8},
|
||||||
|
{"GANG9", GANG9},
|
||||||
|
{"EMERGENCY", EMERGENCY},
|
||||||
|
{"FIREMAN", FIREMAN},
|
||||||
|
{"CRIMINAL", CRIMINAL},
|
||||||
|
{"_UNNAMED", _UNNAMED},
|
||||||
|
{"PROSTITUTE", PROSTITUTE},
|
||||||
|
{"SPECIAL", SPECIAL},
|
||||||
|
};
|
||||||
|
return pedTypes.at(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is orthogonal to object class, it gives
|
||||||
|
* Instances different physical properties.
|
||||||
|
*/
|
||||||
|
struct DynamicObjectData {
|
||||||
|
std::string modelName;
|
||||||
|
float mass; // Kg
|
||||||
|
float turnMass; // Kg m^3
|
||||||
|
float airRes; // fraction
|
||||||
|
float elacticity; // "
|
||||||
|
float bouancy;
|
||||||
|
float uprootForce; // Force
|
||||||
|
float collDamageMulti;
|
||||||
|
/*
|
||||||
|
* 1: change model
|
||||||
|
* 2: split model
|
||||||
|
* 3: smash
|
||||||
|
* 4: change and smash
|
||||||
|
*/
|
||||||
|
uint8_t collDamageFlags;
|
||||||
|
/*
|
||||||
|
* 1: lampost
|
||||||
|
* 2: smallbox
|
||||||
|
* 3: bigbox
|
||||||
|
* 4: fencepart
|
||||||
|
*/
|
||||||
|
uint8_t collResponseFlags;
|
||||||
|
bool cameraAvoid;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,10 +0,0 @@
|
|||||||
#include "data/ObjectData.hpp"
|
|
||||||
|
|
||||||
const ObjectInformation::ObjectClass ObjectData::class_id =
|
|
||||||
ObjectInformation::_class("OBJS");
|
|
||||||
const ObjectInformation::ObjectClass VehicleData::class_id =
|
|
||||||
ObjectInformation::_class("CARS");
|
|
||||||
const ObjectInformation::ObjectClass CharacterData::class_id =
|
|
||||||
ObjectInformation::_class("PEDS");
|
|
||||||
const ObjectInformation::ObjectClass CutsceneObjectData::class_id =
|
|
||||||
ObjectInformation::_class("HIER");
|
|
@ -1,196 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef __GLT_OBJECTDATA_HPP__
|
|
||||||
#define __GLT_OBJECTDATA_HPP__
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <data/PathData.hpp>
|
|
||||||
#ifdef RW_WINDOWS
|
|
||||||
#include <rw_mingw.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef uint16_t ObjectID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores basic information about an Object and it's real type.
|
|
||||||
*/
|
|
||||||
struct ObjectInformation {
|
|
||||||
typedef size_t ObjectClass;
|
|
||||||
static ObjectClass _class(const std::string& name) {
|
|
||||||
return std::hash<std::string>()(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectID ID;
|
|
||||||
const ObjectClass class_type;
|
|
||||||
|
|
||||||
ObjectInformation(const ObjectClass type) : class_type(type) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~ObjectInformation() {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::shared_ptr<ObjectInformation> ObjectInformationPtr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data used by Normal Objects
|
|
||||||
*/
|
|
||||||
struct ObjectData : public ObjectInformation {
|
|
||||||
static const ObjectClass class_id;
|
|
||||||
|
|
||||||
ObjectData() : ObjectInformation(_class("OBJS")) {
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string modelName;
|
|
||||||
std::string textureName;
|
|
||||||
uint8_t numClumps;
|
|
||||||
float drawDistance[3];
|
|
||||||
int32_t flags;
|
|
||||||
bool LOD;
|
|
||||||
|
|
||||||
short timeOn;
|
|
||||||
short timeOff;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
NORMAL_CULL =
|
|
||||||
1, /// Cull model if player doesn't look at it. Ignored in GTA 3.
|
|
||||||
DO_NOT_FADE = 1 << 1, /// Do not fade the object when it is being
|
|
||||||
/// loaded into or out of view.
|
|
||||||
DRAW_LAST = 1 << 2, /// Model is transparent. Render this object after
|
|
||||||
/// all opaque objects, allowing transparencies of
|
|
||||||
/// other objects to be visible through this
|
|
||||||
/// object.
|
|
||||||
ADDITIVE = 1 << 3, /// Render with additive blending. Previous flag
|
|
||||||
/// must be enabled too.
|
|
||||||
IS_SUBWAY = 1 << 4, /// Model is a tunnel, i.e. set the object as
|
|
||||||
/// invisible unless the player enters cull zone
|
|
||||||
/// flag 128. This flag works only with static
|
|
||||||
/// models.
|
|
||||||
IGNORE_LIGHTING = 1 << 5, /// Don't use static lighting, we want
|
|
||||||
/// dynamic if it's possible.
|
|
||||||
NO_ZBUFFER_WRITE =
|
|
||||||
1 << 6, /// Model is a shadow. Disable writing to z-buffer when
|
|
||||||
/// rendering it, allowing transparencies of other objects,
|
|
||||||
/// shadows, and lights to be visible through this object.
|
|
||||||
/// (Not implemented in the PS2 version)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Information loaded from PATH sections
|
|
||||||
std::vector<PathData> paths;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::shared_ptr<ObjectData> ObjectDataPtr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data used by peds
|
|
||||||
*/
|
|
||||||
struct CharacterData : public ObjectInformation {
|
|
||||||
static const ObjectClass class_id;
|
|
||||||
|
|
||||||
CharacterData() : ObjectInformation(_class("PEDS")) {
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string modelName;
|
|
||||||
std::string textureName;
|
|
||||||
std::string type;
|
|
||||||
std::string behaviour;
|
|
||||||
std::string animGroup;
|
|
||||||
uint8_t driveMask;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Stores vehicle data loaded from item definition files.
|
|
||||||
*/
|
|
||||||
struct VehicleData : public ObjectInformation {
|
|
||||||
static const ObjectClass class_id;
|
|
||||||
|
|
||||||
VehicleData() : ObjectInformation(_class("CARS")) {
|
|
||||||
}
|
|
||||||
|
|
||||||
enum VehicleClass {
|
|
||||||
IGNORE = 0,
|
|
||||||
NORMAL = 1,
|
|
||||||
POORFAMILY = 1 << 1,
|
|
||||||
RICHFAMILY = 1 << 2,
|
|
||||||
EXECUTIVE = 1 << 3,
|
|
||||||
WORKER = 1 << 4,
|
|
||||||
BIG = 1 << 5,
|
|
||||||
TAXI = 1 << 6,
|
|
||||||
MOPED = 1 << 7,
|
|
||||||
MOTORBIKE = 1 << 8,
|
|
||||||
LEISUREBOAT = 1 << 9,
|
|
||||||
WORKERBOAT = 1 << 10,
|
|
||||||
BICYCLE = 1 << 11,
|
|
||||||
ONFOOT = 1 << 12,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum VehicleType {
|
|
||||||
CAR,
|
|
||||||
BOAT,
|
|
||||||
TRAIN,
|
|
||||||
PLANE,
|
|
||||||
HELI,
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string modelName;
|
|
||||||
std::string textureName;
|
|
||||||
VehicleType type;
|
|
||||||
std::string handlingID;
|
|
||||||
std::string gameName;
|
|
||||||
VehicleClass classType;
|
|
||||||
uint8_t frequency; // big enough int type?
|
|
||||||
uint8_t lvl; // big enough int type?
|
|
||||||
uint16_t comprules;
|
|
||||||
union { // big enough int types?
|
|
||||||
uint16_t wheelModelID; // used only when type == CAR
|
|
||||||
int16_t modelLOD; // used only when type == PLANE
|
|
||||||
};
|
|
||||||
float wheelScale; // used only when type == CAR
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::shared_ptr<VehicleData> VehicleDataHandle;
|
|
||||||
|
|
||||||
struct CutsceneObjectData : public ObjectInformation {
|
|
||||||
static const ObjectClass class_id;
|
|
||||||
|
|
||||||
CutsceneObjectData() : ObjectInformation(_class("HIER")) {
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string modelName;
|
|
||||||
std::string textureName;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is orthogonal to object class, it gives
|
|
||||||
* Instances different physical properties.
|
|
||||||
*/
|
|
||||||
struct DynamicObjectData {
|
|
||||||
std::string modelName;
|
|
||||||
float mass; // Kg
|
|
||||||
float turnMass; // Kg m^3
|
|
||||||
float airRes; // fraction
|
|
||||||
float elacticity; // "
|
|
||||||
float bouancy;
|
|
||||||
float uprootForce; // Force
|
|
||||||
float collDamageMulti;
|
|
||||||
/*
|
|
||||||
* 1: change model
|
|
||||||
* 2: split model
|
|
||||||
* 3: smash
|
|
||||||
* 4: change and smash
|
|
||||||
*/
|
|
||||||
uint8_t collDamageFlags;
|
|
||||||
/*
|
|
||||||
* 1: lampost
|
|
||||||
* 2: smallbox
|
|
||||||
* 3: bigbox
|
|
||||||
* 4: fencepart
|
|
||||||
*/
|
|
||||||
uint8_t collResponseFlags;
|
|
||||||
bool cameraAvoid;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||||||
#include <data/Model.hpp>
|
#include <data/Model.hpp>
|
||||||
#include <data/ObjectData.hpp>
|
#include <data/ModelData.hpp>
|
||||||
#include <data/WeaponData.hpp>
|
#include <data/WeaponData.hpp>
|
||||||
#include <engine/GameData.hpp>
|
#include <engine/GameData.hpp>
|
||||||
#include <engine/GameState.hpp>
|
#include <engine/GameState.hpp>
|
||||||
@ -11,7 +11,6 @@
|
|||||||
#include <script/SCMFile.hpp>
|
#include <script/SCMFile.hpp>
|
||||||
|
|
||||||
#include <core/Logger.hpp>
|
#include <core/Logger.hpp>
|
||||||
#include <loaders/BackgroundLoader.hpp>
|
|
||||||
#include <loaders/GenericDATLoader.hpp>
|
#include <loaders/GenericDATLoader.hpp>
|
||||||
#include <loaders/LoaderGXT.hpp>
|
#include <loaders/LoaderGXT.hpp>
|
||||||
#include <platform/FileIndex.hpp>
|
#include <platform/FileIndex.hpp>
|
||||||
@ -27,11 +26,7 @@ GameData::GameData(Logger* log, WorkContext* work, const std::string& path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameData::~GameData() {
|
GameData::~GameData() {
|
||||||
for (auto& m : models) {
|
/// @todo don't leak models
|
||||||
if (m.second->resource) {
|
|
||||||
delete m.second->resource;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameData::load() {
|
void GameData::load() {
|
||||||
@ -45,9 +40,6 @@ void GameData::load() {
|
|||||||
loadLevelFile("data/default.dat");
|
loadLevelFile("data/default.dat");
|
||||||
loadLevelFile("data/gta3.dat");
|
loadLevelFile("data/gta3.dat");
|
||||||
|
|
||||||
loadDFF("wheels.dff");
|
|
||||||
loadDFF("weapons.dff");
|
|
||||||
loadDFF("arrow.dff");
|
|
||||||
loadTXD("particle.txd");
|
loadTXD("particle.txd");
|
||||||
loadTXD("icons.txd");
|
loadTXD("icons.txd");
|
||||||
loadTXD("hud.txd");
|
loadTXD("hud.txd");
|
||||||
@ -99,6 +91,9 @@ void GameData::loadLevelFile(const std::string& path) {
|
|||||||
std::transform(name.begin(), name.end(), name.begin(),
|
std::transform(name.begin(), name.end(), name.begin(),
|
||||||
::tolower);
|
::tolower);
|
||||||
loadTXD(name);
|
loadTXD(name);
|
||||||
|
} else if (cmd == "MODELFILE") {
|
||||||
|
auto path = line.substr(space + 1);
|
||||||
|
loadModelFile(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,23 +104,19 @@ void GameData::loadIDE(const std::string& path) {
|
|||||||
LoaderIDE idel;
|
LoaderIDE idel;
|
||||||
|
|
||||||
if (idel.load(systempath)) {
|
if (idel.load(systempath)) {
|
||||||
objectTypes.insert(idel.objects.begin(), idel.objects.end());
|
std::move(idel.objects.begin(), idel.objects.end(),
|
||||||
|
std::inserter(modelinfo, modelinfo.end()));
|
||||||
} else {
|
} else {
|
||||||
logger->error("Data", "Failed to load IDE " + path);
|
logger->error("Data", "Failed to load IDE " + path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t GameData::findModelObject(const std::string model) {
|
uint16_t GameData::findModelObject(const std::string model) {
|
||||||
auto defit = std::find_if(
|
auto defit = std::find_if(modelinfo.begin(), modelinfo.end(),
|
||||||
objectTypes.begin(), objectTypes.end(),
|
[&](const decltype(modelinfo)::value_type& d) {
|
||||||
[&](const decltype(objectTypes)::value_type& d) {
|
return boost::iequals(d.second->name, model);
|
||||||
if (d.second->class_type == ObjectInformation::_class("OBJS")) {
|
});
|
||||||
auto dat = static_cast<ObjectData*>(d.second.get());
|
if (defit != modelinfo.end()) return defit->first;
|
||||||
return boost::iequals(dat->modelName, model);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
if (defit != objectTypes.end()) return defit->first;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,26 +305,118 @@ void GameData::loadTXD(const std::string& name, bool async) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameData::loadDFF(const std::string& name, bool async) {
|
void GameData::getNameAndLod(std::string& name, int& lod) {
|
||||||
auto realname = name.substr(0, name.size() - 4);
|
auto lodpos = name.rfind("_l");
|
||||||
if (models.find(realname) != models.end()) {
|
if (lodpos != std::string::npos) {
|
||||||
|
lod = std::atoi(name.substr(lodpos + 1).c_str());
|
||||||
|
name = name.substr(0, lodpos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Model* GameData::loadClump(const std::string& name) {
|
||||||
|
auto file = index.openFile(name);
|
||||||
|
if (!file) {
|
||||||
|
logger->error("Data", "Failed to load model " + name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
LoaderDFF l;
|
||||||
|
auto m = l.loadFromMemory(file);
|
||||||
|
if (!m) {
|
||||||
|
logger->error("Data", "Error loading model file " + name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameData::loadModelFile(const std::string& name) {
|
||||||
|
auto file = index.openFilePath(name);
|
||||||
|
if (!file) {
|
||||||
|
logger->log("Data", Logger::Error, "Failed to load model file " + name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LoaderDFF l;
|
||||||
|
auto m = l.loadFromMemory(file);
|
||||||
|
if (!m) {
|
||||||
|
logger->log("Data", Logger::Error, "Error loading model file " + name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before starting the job make sure the file isn't loaded again.
|
// Associate the frames with models.
|
||||||
loadedFiles.insert({name, true});
|
for (auto& frame : m->frames) {
|
||||||
|
/// @todo this is useful elsewhere, please move elsewhere
|
||||||
|
std::string name = frame->getName();
|
||||||
|
int lod = 0;
|
||||||
|
getNameAndLod(name, lod);
|
||||||
|
for (auto& model : modelinfo) {
|
||||||
|
auto info = model.second.get();
|
||||||
|
if (info->type() != ModelDataType::SimpleInfo) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (boost::iequals(info->name, name)) {
|
||||||
|
auto simple = static_cast<SimpleModelInfo*>(info);
|
||||||
|
simple->setAtomic(m, lod, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
models[realname] = ModelRef(new ResourceHandle<Model>(realname));
|
void GameData::loadModel(ModelID model) {
|
||||||
|
auto info = modelinfo[model].get();
|
||||||
|
/// @todo replace openFile with API for loading from CDIMAGE archives
|
||||||
|
auto name = info->name;
|
||||||
|
|
||||||
auto job = new BackgroundLoaderJob<Model, LoaderDFF>{
|
// Re-direct special models
|
||||||
workContext, &this->index, name, models[realname]};
|
switch (info->type()) {
|
||||||
|
case ModelDataType::ClumpInfo:
|
||||||
|
// Re-direct the hier objects to the special object ids
|
||||||
|
name = engine->state->specialModels[info->id()];
|
||||||
|
/// @todo remove this from here
|
||||||
|
loadTXD(name + ".txd");
|
||||||
|
break;
|
||||||
|
case ModelDataType::PedInfo:
|
||||||
|
static const std::string specialPrefix("special");
|
||||||
|
if (!name.compare(0, specialPrefix.size(), specialPrefix)) {
|
||||||
|
auto sid = name.substr(specialPrefix.size());
|
||||||
|
unsigned short specialID = std::atoi(sid.c_str());
|
||||||
|
name = engine->state->specialCharacters[specialID];
|
||||||
|
/// @todo remove this from here
|
||||||
|
loadTXD(name + ".txd");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (async) {
|
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||||
workContext->queueJob(job);
|
auto file = index.openFile(name + ".dff");
|
||||||
|
if (!file) {
|
||||||
|
logger->error("Data", "Failed to load model for " +
|
||||||
|
std::to_string(model) + " [" + name + "]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LoaderDFF l;
|
||||||
|
auto m = l.loadFromMemory(file);
|
||||||
|
if (!m) {
|
||||||
|
logger->error("Data",
|
||||||
|
"Error loading model file for " + std::to_string(model));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/// @todo handle timeinfo models correctly.
|
||||||
|
auto isSimple = info->type() == ModelDataType::SimpleInfo;
|
||||||
|
if (isSimple) {
|
||||||
|
auto simple = static_cast<SimpleModelInfo*>(info);
|
||||||
|
// Associate atomics
|
||||||
|
for (auto& frame : m->frames) {
|
||||||
|
auto name = frame->getName();
|
||||||
|
int lod = 0;
|
||||||
|
getNameAndLod(name, lod);
|
||||||
|
simple->setAtomic(m, lod, frame);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
job->work();
|
// Associate clumps
|
||||||
job->complete();
|
auto clump = static_cast<ClumpModelInfo*>(info);
|
||||||
delete job;
|
clump->setModel(m);
|
||||||
|
/// @todo how is LOD handled for clump objects?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,9 +119,24 @@ public:
|
|||||||
void loadTXD(const std::string& name, bool async = false);
|
void loadTXD(const std::string& name, bool async = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to load a DFF or does nothing if is already loaded
|
* Converts combined {name}_l{LOD} into name and lod.
|
||||||
*/
|
*/
|
||||||
void loadDFF(const std::string& name, bool async = false);
|
static void getNameAndLod(std::string& name, int& lod);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads an archived model and returns it directly
|
||||||
|
*/
|
||||||
|
Model* loadClump(const std::string& name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a DFF and associates its atomics with models.
|
||||||
|
*/
|
||||||
|
void loadModelFile(const std::string& name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads and associates a model's data
|
||||||
|
*/
|
||||||
|
void loadModel(ModelID model);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads an IFP file containing animations
|
* Loads an IFP file containing animations
|
||||||
@ -170,20 +185,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
std::map<std::string, ZoneData> zones;
|
std::map<std::string, ZoneData> zones;
|
||||||
|
|
||||||
/**
|
std::unordered_map<ModelID, std::unique_ptr<BaseModelInfo>> modelinfo;
|
||||||
* Object Definitions
|
|
||||||
*/
|
|
||||||
std::map<ObjectID, ObjectInformationPtr> objectTypes;
|
|
||||||
|
|
||||||
uint16_t findModelObject(const std::string model);
|
uint16_t findModelObject(const std::string model);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
std::shared_ptr<T> findObjectType(ObjectID id) {
|
T* findModelInfo(ModelID id) {
|
||||||
auto f = objectTypes.find(id);
|
auto f = modelinfo.find(id);
|
||||||
/// @TODO don't instanciate an object here just to read .type
|
if (f != modelinfo.end() && f->second->type() == T::kType) {
|
||||||
T tmp;
|
return static_cast<T*>(f->second.get());
|
||||||
if (f != objectTypes.end() && f->second->class_type == tmp.class_type) {
|
|
||||||
return std::static_pointer_cast<T>(f->second);
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -214,11 +224,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
WeatherLoader weatherLoader;
|
WeatherLoader weatherLoader;
|
||||||
|
|
||||||
/**
|
|
||||||
* Loaded models
|
|
||||||
*/
|
|
||||||
std::map<std::string, ResourceHandle<Model>::Ref> models;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loaded textures (Textures are ID by name and alpha pairs)
|
* Loaded textures (Textures are ID by name and alpha pairs)
|
||||||
*/
|
*/
|
||||||
|
@ -140,10 +140,10 @@ bool GameWorld::placeItems(const std::string& name) {
|
|||||||
for (auto& p : instancePool.objects) {
|
for (auto& p : instancePool.objects) {
|
||||||
auto object = p.second;
|
auto object = p.second;
|
||||||
InstanceObject* instance = static_cast<InstanceObject*>(object);
|
InstanceObject* instance = static_cast<InstanceObject*>(object);
|
||||||
if (!instance->object->LOD &&
|
auto modelinfo = instance->getModelInfo<SimpleModelInfo>();
|
||||||
instance->object->modelName.length() > 3) {
|
if (!modelinfo->LOD && modelinfo->name.length() > 3) {
|
||||||
auto lodInstit = modelInstances.find(
|
auto lodInstit =
|
||||||
"LOD" + instance->object->modelName.substr(3));
|
modelInstances.find("LOD" + modelinfo->name.substr(3));
|
||||||
if (lodInstit != modelInstances.end()) {
|
if (lodInstit != modelInstances.end()) {
|
||||||
instance->LODinstance = lodInstit->second;
|
instance->LODinstance = lodInstit->second;
|
||||||
}
|
}
|
||||||
@ -162,30 +162,28 @@ bool GameWorld::placeItems(const std::string& name) {
|
|||||||
InstanceObject* GameWorld::createInstance(const uint16_t id,
|
InstanceObject* GameWorld::createInstance(const uint16_t id,
|
||||||
const glm::vec3& pos,
|
const glm::vec3& pos,
|
||||||
const glm::quat& rot) {
|
const glm::quat& rot) {
|
||||||
auto oi = data->findObjectType<ObjectData>(id);
|
auto oi = data->findModelInfo<SimpleModelInfo>(id);
|
||||||
if (oi) {
|
if (oi) {
|
||||||
std::string modelname = oi->modelName;
|
// Request loading of the model if it isn't loaded already.
|
||||||
std::string texturename = oi->textureName;
|
/// @todo implment streaming properly
|
||||||
|
if (!oi->isLoaded()) {
|
||||||
|
data->loadModel(oi->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string modelname = oi->name;
|
||||||
|
std::string texturename = oi->textureslot;
|
||||||
|
|
||||||
std::transform(std::begin(modelname), std::end(modelname),
|
std::transform(std::begin(modelname), std::end(modelname),
|
||||||
std::begin(modelname), tolower);
|
std::begin(modelname), tolower);
|
||||||
std::transform(std::begin(texturename), std::end(texturename),
|
std::transform(std::begin(texturename), std::end(texturename),
|
||||||
std::begin(texturename), tolower);
|
std::begin(texturename), tolower);
|
||||||
|
|
||||||
// Ensure the relevant data is loaded.
|
|
||||||
if (!oi->modelName.empty()) {
|
|
||||||
if (modelname != "null") {
|
|
||||||
data->loadDFF(modelname + ".dff", false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!texturename.empty()) {
|
if (!texturename.empty()) {
|
||||||
data->loadTXD(texturename + ".txd", true);
|
data->loadTXD(texturename + ".txd", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelRef m = data->models[modelname];
|
|
||||||
|
|
||||||
// Check for dynamic data.
|
// Check for dynamic data.
|
||||||
auto dyit = data->dynamicObjectData.find(oi->modelName);
|
auto dyit = data->dynamicObjectData.find(oi->name);
|
||||||
std::shared_ptr<DynamicObjectData> dydata;
|
std::shared_ptr<DynamicObjectData> dydata;
|
||||||
if (dyit != data->dynamicObjectData.end()) {
|
if (dyit != data->dynamicObjectData.end()) {
|
||||||
dydata = dyit->second;
|
dydata = dyit->second;
|
||||||
@ -197,12 +195,12 @@ InstanceObject* GameWorld::createInstance(const uint16_t id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto instance = new InstanceObject(
|
auto instance = new InstanceObject(
|
||||||
this, pos, rot, m, glm::vec3(1.f, 1.f, 1.f), oi, nullptr, dydata);
|
this, pos, rot, glm::vec3(1.f, 1.f, 1.f), oi, nullptr, dydata);
|
||||||
|
|
||||||
instancePool.insert(instance);
|
instancePool.insert(instance);
|
||||||
allObjects.push_back(instance);
|
allObjects.push_back(instance);
|
||||||
|
|
||||||
modelInstances.insert({oi->modelName, instance});
|
modelInstances.insert({oi->name, instance});
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@ -250,62 +248,34 @@ void GameWorld::cleanupTraffic(const ViewCamera& focus) {
|
|||||||
CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id,
|
CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id,
|
||||||
const glm::vec3& pos,
|
const glm::vec3& pos,
|
||||||
const glm::quat& rot) {
|
const glm::quat& rot) {
|
||||||
std::string modelname;
|
auto modelinfo = data->modelinfo[id].get();
|
||||||
|
|
||||||
|
if (!modelinfo) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto clumpmodel = static_cast<ClumpModelInfo*>(modelinfo);
|
||||||
std::string texturename;
|
std::string texturename;
|
||||||
|
|
||||||
auto type = data->objectTypes.find(id);
|
if (!clumpmodel->isLoaded()) {
|
||||||
if (type != data->objectTypes.end()) {
|
data->loadModel(id);
|
||||||
if (type->second->class_type == ObjectInformation::_class("HIER")) {
|
|
||||||
modelname = state->specialModels[id];
|
|
||||||
texturename = state->specialModels[id];
|
|
||||||
} else {
|
|
||||||
if (type->second->class_type == ObjectInformation::_class("OBJS")) {
|
|
||||||
auto v = static_cast<ObjectData*>(type->second.get());
|
|
||||||
modelname = v->modelName;
|
|
||||||
texturename = v->textureName;
|
|
||||||
} else if (type->second->class_type ==
|
|
||||||
ObjectInformation::_class("PEDS")) {
|
|
||||||
auto v = static_cast<CharacterData*>(type->second.get());
|
|
||||||
modelname = v->modelName;
|
|
||||||
texturename = v->textureName;
|
|
||||||
|
|
||||||
static std::string specialPrefix("special");
|
|
||||||
if (!modelname.compare(0, specialPrefix.size(),
|
|
||||||
specialPrefix)) {
|
|
||||||
auto sid = modelname.substr(specialPrefix.size());
|
|
||||||
unsigned short specialID = std::atoi(sid.c_str());
|
|
||||||
modelname = state->specialCharacters[specialID];
|
|
||||||
texturename = state->specialCharacters[specialID];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
auto model = clumpmodel->getModel();
|
||||||
|
|
||||||
|
texturename = modelinfo->textureslot;
|
||||||
|
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
auto playerobj = pedestrianPool.find(state->playerObject);
|
auto playerobj = pedestrianPool.find(state->playerObject);
|
||||||
if (playerobj) {
|
if (playerobj) {
|
||||||
modelname = playerobj->model->name;
|
model = playerobj->getModel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the relevant data is loaded.
|
|
||||||
if (modelname.empty()) {
|
|
||||||
logger->error(
|
|
||||||
"World", "Cutscene object " + std::to_string(id) + " has no model");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (modelname != "null") {
|
|
||||||
data->loadDFF(modelname + ".dff", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!texturename.empty()) {
|
if (!texturename.empty()) {
|
||||||
data->loadTXD(texturename + ".txd", true);
|
data->loadTXD(texturename + ".txd", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelRef m = data->models[modelname];
|
auto instance = new CutsceneObject(this, pos, rot, model, modelinfo);
|
||||||
|
|
||||||
auto instance = new CutsceneObject(this, pos, rot, m);
|
|
||||||
|
|
||||||
cutscenePool.insert(instance);
|
cutscenePool.insert(instance);
|
||||||
allObjects.push_back(instance);
|
allObjects.push_back(instance);
|
||||||
@ -316,171 +286,149 @@ CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id,
|
|||||||
VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos,
|
VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos,
|
||||||
const glm::quat& rot,
|
const glm::quat& rot,
|
||||||
GameObjectID gid) {
|
GameObjectID gid) {
|
||||||
auto vti = data->findObjectType<VehicleData>(id);
|
auto vti = data->findModelInfo<VehicleModelInfo>(id);
|
||||||
if (vti) {
|
if (!vti) {
|
||||||
logger->info("World", "Creating Vehicle ID " + std::to_string(id) +
|
return nullptr;
|
||||||
" (" + vti->gameName + ")");
|
}
|
||||||
|
logger->info("World", "Creating Vehicle ID " + std::to_string(id) + " (" +
|
||||||
|
vti->vehiclename_ + ")");
|
||||||
|
|
||||||
if (!vti->modelName.empty()) {
|
if (!vti->isLoaded()) {
|
||||||
data->loadDFF(vti->modelName + ".dff");
|
data->loadModel(id);
|
||||||
}
|
}
|
||||||
if (!vti->textureName.empty()) {
|
|
||||||
data->loadTXD(vti->textureName + ".txd");
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::u8vec3 prim(255), sec(128);
|
if (!vti->textureslot.empty()) {
|
||||||
auto palit = data->vehiclePalettes.find(
|
data->loadTXD(vti->textureslot + ".txd");
|
||||||
vti->modelName); // modelname is conveniently lowercase (usually)
|
}
|
||||||
if (palit != data->vehiclePalettes.end() && palit->second.size() > 0) {
|
|
||||||
std::uniform_int_distribution<int> uniform(
|
|
||||||
0, palit->second.size() - 1);
|
|
||||||
int set = uniform(randomEngine);
|
|
||||||
prim = data->vehicleColours[palit->second[set].first];
|
|
||||||
sec = data->vehicleColours[palit->second[set].second];
|
|
||||||
} else {
|
|
||||||
logger->warning("World",
|
|
||||||
"No colour palette for vehicle " + vti->modelName);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto wi = data->findObjectType<ObjectData>(vti->wheelModelID);
|
glm::u8vec3 prim(255), sec(128);
|
||||||
if (wi) {
|
auto palit = data->vehiclePalettes.find(
|
||||||
if (!wi->textureName.empty()) {
|
vti->name); // modelname is conveniently lowercase (usually)
|
||||||
data->loadTXD(wi->textureName + ".txd");
|
if (palit != data->vehiclePalettes.end() && palit->second.size() > 0) {
|
||||||
}
|
std::uniform_int_distribution<int> uniform(0, palit->second.size() - 1);
|
||||||
}
|
int set = uniform(randomEngine);
|
||||||
|
prim = data->vehicleColours[palit->second[set].first];
|
||||||
|
sec = data->vehicleColours[palit->second[set].second];
|
||||||
|
} else {
|
||||||
|
logger->warning("World", "No colour palette for vehicle " + vti->name);
|
||||||
|
}
|
||||||
|
|
||||||
ModelRef& m = data->models[vti->modelName];
|
auto model = vti->getModel();
|
||||||
auto model = m->resource;
|
auto info = data->vehicleInfo.find(vti->handling_);
|
||||||
auto info = data->vehicleInfo.find(vti->handlingID);
|
if (model && info != data->vehicleInfo.end()) {
|
||||||
if (model && info != data->vehicleInfo.end()) {
|
if (info->second->wheels.size() == 0 &&
|
||||||
if (info->second->wheels.size() == 0 &&
|
info->second->seats.size() == 0) {
|
||||||
info->second->seats.size() == 0) {
|
for (const ModelFrame* f : model->frames) {
|
||||||
for (const ModelFrame* f : model->frames) {
|
const std::string& name = f->getName();
|
||||||
const std::string& name = f->getName();
|
|
||||||
|
|
||||||
if (name.size() > 5 && name.substr(0, 5) == "wheel") {
|
if (name.size() > 5 && name.substr(0, 5) == "wheel") {
|
||||||
auto frameTrans = f->getMatrix();
|
auto frameTrans = f->getMatrix();
|
||||||
info->second->wheels.push_back(
|
info->second->wheels.push_back({glm::vec3(frameTrans[3])});
|
||||||
{glm::vec3(frameTrans[3])});
|
}
|
||||||
}
|
if (name == "ped_frontseat") {
|
||||||
if (name == "ped_frontseat") {
|
auto p = f->getDefaultTranslation();
|
||||||
auto p = f->getDefaultTranslation();
|
// Left seat
|
||||||
// Left seat
|
p.x = -p.x;
|
||||||
p.x = -p.x;
|
info->second->seats.front.push_back({p});
|
||||||
info->second->seats.front.push_back({p});
|
// Right seat
|
||||||
// Right seat
|
p.x = -p.x;
|
||||||
p.x = -p.x;
|
info->second->seats.front.push_back({p});
|
||||||
info->second->seats.front.push_back({p});
|
}
|
||||||
}
|
if (name == "ped_backseat") {
|
||||||
if (name == "ped_backseat") {
|
// @todo how does this work for the barracks, ambulance
|
||||||
// @todo how does this work for the barracks, ambulance
|
// or coach?
|
||||||
// or coach?
|
auto p = f->getDefaultTranslation();
|
||||||
auto p = f->getDefaultTranslation();
|
// Left seat
|
||||||
// Left seat
|
p.x = -p.x;
|
||||||
p.x = -p.x;
|
info->second->seats.back.push_back({p});
|
||||||
info->second->seats.back.push_back({p});
|
// Right seat
|
||||||
// Right seat
|
p.x = -p.x;
|
||||||
p.x = -p.x;
|
info->second->seats.back.push_back({p});
|
||||||
info->second->seats.back.push_back({p});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto vehicle =
|
|
||||||
new VehicleObject{this, pos, rot, m, vti, info->second, prim, sec};
|
|
||||||
vehicle->setGameObjectID(gid);
|
|
||||||
|
|
||||||
vehiclePool.insert(vehicle);
|
|
||||||
allObjects.push_back(vehicle);
|
|
||||||
|
|
||||||
return vehicle;
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
|
auto vehicle =
|
||||||
|
new VehicleObject{this, pos, rot, vti, info->second, prim, sec};
|
||||||
|
vehicle->setGameObjectID(gid);
|
||||||
|
|
||||||
|
vehiclePool.insert(vehicle);
|
||||||
|
allObjects.push_back(vehicle);
|
||||||
|
|
||||||
|
return vehicle;
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterObject* GameWorld::createPedestrian(const uint16_t id,
|
CharacterObject* GameWorld::createPedestrian(const uint16_t id,
|
||||||
const glm::vec3& pos,
|
const glm::vec3& pos,
|
||||||
const glm::quat& rot,
|
const glm::quat& rot,
|
||||||
GameObjectID gid) {
|
GameObjectID gid) {
|
||||||
auto pt = data->findObjectType<CharacterData>(id);
|
auto pt = data->findModelInfo<PedModelInfo>(id);
|
||||||
if (pt) {
|
if (!pt) {
|
||||||
std::string modelname = pt->modelName;
|
return nullptr;
|
||||||
std::string texturename = pt->textureName;
|
|
||||||
|
|
||||||
// Ensure the relevant data is loaded.
|
|
||||||
if (!pt->modelName.empty()) {
|
|
||||||
// Some model names have special meanings.
|
|
||||||
/// @todo Should CharacterObjects handle this?
|
|
||||||
static std::string specialPrefix("special");
|
|
||||||
if (!modelname.compare(0, specialPrefix.size(), specialPrefix)) {
|
|
||||||
auto sid = modelname.substr(specialPrefix.size());
|
|
||||||
unsigned short specialID = std::atoi(sid.c_str());
|
|
||||||
modelname = state->specialCharacters[specialID];
|
|
||||||
texturename = state->specialCharacters[specialID];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (modelname != "null") {
|
|
||||||
data->loadDFF(modelname + ".dff");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!texturename.empty()) {
|
|
||||||
data->loadTXD(texturename + ".txd");
|
|
||||||
}
|
|
||||||
|
|
||||||
ModelRef m = data->models[modelname];
|
|
||||||
|
|
||||||
if (m && m->resource) {
|
|
||||||
auto ped = new CharacterObject(this, pos, rot, m, pt);
|
|
||||||
ped->setGameObjectID(gid);
|
|
||||||
new DefaultAIController(ped);
|
|
||||||
pedestrianPool.insert(ped);
|
|
||||||
allObjects.push_back(ped);
|
|
||||||
return ped;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
|
auto isSpecial = pt->name.compare(0, 7, "special") == 0;
|
||||||
|
if (!pt->isLoaded() || isSpecial) {
|
||||||
|
data->loadModel(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string texturename = pt->textureslot;
|
||||||
|
|
||||||
|
if (!texturename.empty()) {
|
||||||
|
data->loadTXD(texturename + ".txd");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ped = new CharacterObject(this, pos, rot, pt);
|
||||||
|
ped->setGameObjectID(gid);
|
||||||
|
new DefaultAIController(ped);
|
||||||
|
pedestrianPool.insert(ped);
|
||||||
|
allObjects.push_back(ped);
|
||||||
|
return ped;
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterObject* GameWorld::createPlayer(const glm::vec3& pos,
|
CharacterObject* GameWorld::createPlayer(const glm::vec3& pos,
|
||||||
const glm::quat& rot,
|
const glm::quat& rot,
|
||||||
GameObjectID gid) {
|
GameObjectID gid) {
|
||||||
// Player object ID is hardcoded to 0.
|
// Player object ID is hardcoded to 0.
|
||||||
auto pt = data->findObjectType<CharacterData>(0);
|
auto pt = data->findModelInfo<PedModelInfo>(0);
|
||||||
if (pt) {
|
if (!pt) {
|
||||||
// Model name is also hardcoded.
|
return nullptr;
|
||||||
std::string modelname = "player";
|
|
||||||
std::string texturename = "player";
|
|
||||||
|
|
||||||
// Ensure the relevant data is loaded.
|
|
||||||
data->loadDFF(modelname + ".dff");
|
|
||||||
data->loadTXD(texturename + ".txd");
|
|
||||||
|
|
||||||
ModelRef m = data->models[modelname];
|
|
||||||
|
|
||||||
if (m && m->resource) {
|
|
||||||
auto ped = new CharacterObject(this, pos, rot, m, nullptr);
|
|
||||||
ped->setGameObjectID(gid);
|
|
||||||
ped->setLifetime(GameObject::PlayerLifetime);
|
|
||||||
players.push_back(new PlayerController(ped));
|
|
||||||
pedestrianPool.insert(ped);
|
|
||||||
allObjects.push_back(ped);
|
|
||||||
return ped;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
|
// Model name is also hardcoded.
|
||||||
|
std::string modelname = "player";
|
||||||
|
std::string texturename = "player";
|
||||||
|
|
||||||
|
if (!pt->isLoaded()) {
|
||||||
|
auto model = data->loadClump(modelname + ".dff");
|
||||||
|
pt->setModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->loadTXD(texturename + ".txd");
|
||||||
|
|
||||||
|
auto ped = new CharacterObject(this, pos, rot, pt);
|
||||||
|
ped->setGameObjectID(gid);
|
||||||
|
ped->setLifetime(GameObject::PlayerLifetime);
|
||||||
|
players.push_back(new PlayerController(ped));
|
||||||
|
pedestrianPool.insert(ped);
|
||||||
|
allObjects.push_back(ped);
|
||||||
|
return ped;
|
||||||
}
|
}
|
||||||
|
|
||||||
PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) {
|
PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) {
|
||||||
auto modelInfo = data->findObjectType<ObjectData>(id);
|
auto modelInfo = data->modelinfo[id].get();
|
||||||
|
|
||||||
RW_CHECK(modelInfo != nullptr, "Pickup Object Data is not found");
|
RW_CHECK(modelInfo != nullptr, "Pickup Object Data is not found");
|
||||||
if (modelInfo == nullptr) {
|
if (modelInfo == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->loadDFF(modelInfo->modelName + ".dff");
|
if (!modelInfo->isLoaded()) {
|
||||||
data->loadTXD(modelInfo->textureName + ".txd");
|
data->loadModel(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->loadTXD(modelInfo->textureslot + ".txd");
|
||||||
|
|
||||||
PickupObject* pickup = nullptr;
|
PickupObject* pickup = nullptr;
|
||||||
auto pickuptype = (PickupObject::PickupType)type;
|
auto pickuptype = (PickupObject::PickupType)type;
|
||||||
@ -492,10 +440,10 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) {
|
|||||||
|
|
||||||
// If nothing, create a generic pickup instead of an item pickup
|
// If nothing, create a generic pickup instead of an item pickup
|
||||||
if (it != inventoryItems.end()) {
|
if (it != inventoryItems.end()) {
|
||||||
pickup = new ItemPickup(this, pos, pickuptype, *it);
|
pickup = new ItemPickup(this, pos, modelInfo, pickuptype, *it);
|
||||||
} else {
|
} else {
|
||||||
RW_UNIMPLEMENTED("Non-weapon pickups");
|
RW_UNIMPLEMENTED("Non-weapon pickups");
|
||||||
pickup = new PickupObject(this, pos, id, pickuptype);
|
pickup = new PickupObject(this, pos, modelInfo, pickuptype);
|
||||||
}
|
}
|
||||||
|
|
||||||
pickupPool.insert(pickup);
|
pickupPool.insert(pickup);
|
||||||
@ -861,20 +809,32 @@ bool GameWorld::isCutsceneDone() {
|
|||||||
|
|
||||||
void GameWorld::loadSpecialCharacter(const unsigned short index,
|
void GameWorld::loadSpecialCharacter(const unsigned short index,
|
||||||
const std::string& name) {
|
const std::string& name) {
|
||||||
|
constexpr uint16_t kFirstSpecialActor = 26;
|
||||||
|
logger->info("Data", "Loading special actor " + name + " to " +
|
||||||
|
std::to_string(index));
|
||||||
|
auto modelid = kFirstSpecialActor + index - 1;
|
||||||
|
auto model = data->findModelInfo<PedModelInfo>(modelid);
|
||||||
|
if (model && model->isLoaded()) {
|
||||||
|
model->unload();
|
||||||
|
}
|
||||||
std::string lowerName(name);
|
std::string lowerName(name);
|
||||||
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(),
|
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(),
|
||||||
::tolower);
|
::tolower);
|
||||||
/// @todo a bit more smarter than this
|
|
||||||
state->specialCharacters[index] = lowerName;
|
state->specialCharacters[index] = lowerName;
|
||||||
data->loadDFF(lowerName + ".dff");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameWorld::loadSpecialModel(const unsigned short index,
|
void GameWorld::loadSpecialModel(const unsigned short index,
|
||||||
const std::string& name) {
|
const std::string& name) {
|
||||||
|
logger->info("Data", "Loading cutscene object " + name + " to " +
|
||||||
|
std::to_string(index));
|
||||||
|
// Tell the HIER model to discard the currently loaded model
|
||||||
|
auto model = data->findModelInfo<ClumpModelInfo>(index);
|
||||||
|
if (model && model->isLoaded()) {
|
||||||
|
model->unload();
|
||||||
|
}
|
||||||
std::string lowerName(name);
|
std::string lowerName(name);
|
||||||
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(),
|
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(),
|
||||||
::tolower);
|
::tolower);
|
||||||
/// @todo a bit more smarter than this
|
|
||||||
state->specialModels[index] = lowerName;
|
state->specialModels[index] = lowerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ class VehicleObject;
|
|||||||
class PickupObject;
|
class PickupObject;
|
||||||
|
|
||||||
class ViewCamera;
|
class ViewCamera;
|
||||||
#include <data/ObjectData.hpp>
|
#include <data/ModelData.hpp>
|
||||||
#include <render/VisualFX.hpp>
|
#include <render/VisualFX.hpp>
|
||||||
|
|
||||||
struct BlipData;
|
struct BlipData;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#include <objects/ProjectileObject.hpp>
|
#include <objects/ProjectileObject.hpp>
|
||||||
|
|
||||||
void WeaponItem::fireHitscan(CharacterObject* owner) {
|
void WeaponItem::fireHitscan(CharacterObject* owner) {
|
||||||
auto handFrame = owner->model->resource->findFrame("srhand");
|
auto handFrame = owner->getModel()->findFrame("srhand");
|
||||||
glm::mat4 handMatrix;
|
glm::mat4 handMatrix;
|
||||||
if (handFrame) {
|
if (handFrame) {
|
||||||
while (handFrame->getParent()) {
|
while (handFrame->getParent()) {
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <data/ResourceHandle.hpp>
|
|
||||||
#include <job/WorkContext.hpp>
|
|
||||||
#include <platform/FileIndex.hpp>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of a worker that loads a resource in the background.
|
|
||||||
*/
|
|
||||||
template <class T, class L>
|
|
||||||
class BackgroundLoaderJob : public WorkJob {
|
|
||||||
public:
|
|
||||||
typedef typename ResourceHandle<T>::Ref TypeRef;
|
|
||||||
|
|
||||||
BackgroundLoaderJob(WorkContext* context, FileIndex* index,
|
|
||||||
const std::string& file, const TypeRef& ref)
|
|
||||||
: WorkJob(context), index(index), filename(file), resourceRef(ref) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void work() {
|
|
||||||
data = index->openFile(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
void complete() {
|
|
||||||
if (data) {
|
|
||||||
L loader;
|
|
||||||
|
|
||||||
resourceRef->resource = loader.loadFromMemory(data);
|
|
||||||
resourceRef->state = RW::Loaded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
FileIndex* index;
|
|
||||||
std::string filename;
|
|
||||||
FileHandle data;
|
|
||||||
TypeRef resourceRef;
|
|
||||||
};
|
|
@ -4,7 +4,7 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include <data/ObjectData.hpp>
|
#include <data/ModelData.hpp>
|
||||||
#include <data/WeaponData.hpp>
|
#include <data/WeaponData.hpp>
|
||||||
#include <objects/VehicleInfo.hpp>
|
#include <objects/VehicleInfo.hpp>
|
||||||
|
|
||||||
|
@ -48,34 +48,35 @@ bool LoaderIDE::load(const std::string &filename) {
|
|||||||
line.end());
|
line.end());
|
||||||
|
|
||||||
std::stringstream strstream(line);
|
std::stringstream strstream(line);
|
||||||
|
std::string buff;
|
||||||
|
|
||||||
switch (section) {
|
switch (section) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case OBJS:
|
case OBJS:
|
||||||
case TOBJ: { // Supports Type 1, 2 and 3
|
case TOBJ: { // Supports Type 1, 2 and 3
|
||||||
std::shared_ptr<ObjectData> objs(new ObjectData);
|
auto objs =
|
||||||
|
std::unique_ptr<SimpleModelInfo>(new SimpleModelInfo);
|
||||||
|
|
||||||
std::string id, numClumps, flags, modelName, textureName;
|
getline(strstream, buff, ',');
|
||||||
|
objs->setModelID(atoi(buff.c_str()));
|
||||||
|
|
||||||
// Read the content of the line
|
getline(strstream, objs->name, ',');
|
||||||
getline(strstream, id, ',');
|
getline(strstream, objs->textureslot, ',');
|
||||||
getline(strstream, modelName, ',');
|
|
||||||
getline(strstream, textureName, ',');
|
|
||||||
getline(strstream, numClumps, ',');
|
|
||||||
|
|
||||||
objs->numClumps = atoi(numClumps.c_str());
|
getline(strstream, buff, ',');
|
||||||
for (size_t i = 0; i < objs->numClumps; i++) {
|
objs->setNumAtomics(atoi(buff.c_str()));
|
||||||
std::string drawDistance;
|
|
||||||
getline(strstream, drawDistance, ',');
|
for (int i = 0; i < objs->getNumAtomics(); i++) {
|
||||||
objs->drawDistance[i] = atoi(drawDistance.c_str());
|
getline(strstream, buff, ',');
|
||||||
|
objs->setLodDistance(i, atof(buff.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
getline(strstream, flags, ',');
|
getline(strstream, buff, ',');
|
||||||
|
objs->flags = atoi(buff.c_str());
|
||||||
|
|
||||||
// Keep reading TOBJ data
|
// Keep reading TOBJ data
|
||||||
if (section == LoaderIDE::TOBJ) {
|
if (section == LoaderIDE::TOBJ) {
|
||||||
std::string buff;
|
|
||||||
getline(strstream, buff, ',');
|
getline(strstream, buff, ',');
|
||||||
objs->timeOn = atoi(buff.c_str());
|
objs->timeOn = atoi(buff.c_str());
|
||||||
getline(strstream, buff, ',');
|
getline(strstream, buff, ',');
|
||||||
@ -85,104 +86,82 @@ bool LoaderIDE::load(const std::string &filename) {
|
|||||||
objs->timeOff = 24;
|
objs->timeOff = 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put stuff in our struct
|
/// @todo Figure out how LOD stuff is intended to work
|
||||||
objs->ID = atoi(id.c_str());
|
if (objs->name.find("LOD", 0, 3) != std::string::npos &&
|
||||||
objs->flags = atoi(flags.c_str());
|
objs->name != "LODistancoast01") {
|
||||||
objs->modelName = modelName;
|
|
||||||
objs->textureName = textureName;
|
|
||||||
objs->LOD = false;
|
|
||||||
|
|
||||||
if (modelName.find("LOD", 0, 3) != modelName.npos &&
|
|
||||||
modelName != "LODistancoast01") {
|
|
||||||
objs->LOD = true;
|
objs->LOD = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
objects.insert({objs->ID, objs});
|
objects.emplace(objs->id(), std::move(objs));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CARS: {
|
case CARS: {
|
||||||
std::shared_ptr<VehicleData> cars(new VehicleData);
|
auto cars =
|
||||||
|
std::unique_ptr<VehicleModelInfo>(new VehicleModelInfo);
|
||||||
|
|
||||||
std::string id, type, classType, frequency, lvl, comprules,
|
getline(strstream, buff, ',');
|
||||||
wheelModelID, wheelScale;
|
cars->setModelID(std::atoi(buff.c_str()));
|
||||||
|
|
||||||
getline(strstream, id, ',');
|
getline(strstream, cars->name, ',');
|
||||||
getline(strstream, cars->modelName, ',');
|
getline(strstream, cars->textureslot, ',');
|
||||||
getline(strstream, cars->textureName, ',');
|
|
||||||
getline(strstream, type, ',');
|
|
||||||
getline(strstream, cars->handlingID, ',');
|
|
||||||
getline(strstream, cars->gameName, ',');
|
|
||||||
getline(strstream, classType, ',');
|
|
||||||
getline(strstream, frequency, ',');
|
|
||||||
getline(strstream, lvl, ',');
|
|
||||||
getline(strstream, comprules, ',');
|
|
||||||
getline(strstream, wheelModelID, ',');
|
|
||||||
getline(strstream, wheelScale, ',');
|
|
||||||
|
|
||||||
cars->ID = atoi(id.c_str());
|
getline(strstream, buff, ',');
|
||||||
cars->frequency = atoi(frequency.c_str());
|
cars->vehicletype_ =
|
||||||
cars->lvl = atoi(lvl.c_str());
|
VehicleModelInfo::findVehicleType(buff);
|
||||||
cars->comprules = atoi(comprules.c_str());
|
|
||||||
|
|
||||||
if (type == "car") {
|
getline(strstream, cars->handling_, ',');
|
||||||
cars->type = VehicleData::CAR;
|
getline(strstream, cars->vehiclename_, ',');
|
||||||
cars->wheelModelID = atoi(wheelModelID.c_str());
|
getline(strstream, buff, ',');
|
||||||
cars->wheelScale = atof(wheelScale.c_str());
|
cars->vehicleclass_ =
|
||||||
} else if (type == "boat") {
|
VehicleModelInfo::findVehicleClass(buff);
|
||||||
cars->type = VehicleData::BOAT;
|
|
||||||
} else if (type == "train") {
|
|
||||||
cars->type = VehicleData::TRAIN;
|
|
||||||
cars->modelLOD = atoi(wheelModelID.c_str());
|
|
||||||
} else if (type == "plane") {
|
|
||||||
cars->type = VehicleData::PLANE;
|
|
||||||
} else if (type == "heli") {
|
|
||||||
cars->type = VehicleData::HELI;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::map<VehicleData::VehicleClass, std::string>
|
getline(strstream, buff, ',');
|
||||||
classTypes{
|
cars->frequency_ = std::atoi(buff.c_str());
|
||||||
{VehicleData::IGNORE, "ignore"},
|
|
||||||
{VehicleData::NORMAL, "normal"},
|
getline(strstream, buff, ',');
|
||||||
{VehicleData::POORFAMILY, "poorfamily"},
|
cars->level_ = std::atoi(buff.c_str());
|
||||||
{VehicleData::RICHFAMILY, "richfamily"},
|
|
||||||
{VehicleData::EXECUTIVE, "executive"},
|
getline(strstream, buff, ',');
|
||||||
{VehicleData::WORKER, "worker"},
|
cars->componentrules_ = std::atoi(buff.c_str());
|
||||||
{VehicleData::BIG, "big"},
|
|
||||||
{VehicleData::TAXI, "taxi"},
|
switch (cars->vehicletype_) {
|
||||||
{VehicleData::MOPED, "moped"},
|
case VehicleModelInfo::CAR:
|
||||||
{VehicleData::MOTORBIKE, "motorbike"},
|
getline(strstream, buff, ',');
|
||||||
{VehicleData::LEISUREBOAT, "leisureboat"},
|
cars->wheelmodel_ = std::atoi(buff.c_str());
|
||||||
{VehicleData::WORKERBOAT, "workerboat"},
|
getline(strstream, buff, ',');
|
||||||
{VehicleData::BICYCLE, "bicycle"},
|
cars->wheelscale_ = std::atof(buff.c_str());
|
||||||
{VehicleData::ONFOOT, "onfoot"},
|
break;
|
||||||
};
|
case VehicleModelInfo::PLANE:
|
||||||
for (auto &a : classTypes) {
|
/// @todo load LOD
|
||||||
if (classType == a.second) {
|
getline(strstream, buff, ',');
|
||||||
cars->classType = a.first;
|
// cars->planeLOD_ = std::atoi(buff.c_str());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
objects.insert({cars->ID, cars});
|
objects.emplace(cars->id(), std::move(cars));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PEDS: {
|
case PEDS: {
|
||||||
std::shared_ptr<CharacterData> peds(new CharacterData);
|
auto peds = std::unique_ptr<PedModelInfo>(new PedModelInfo);
|
||||||
|
|
||||||
std::string id, driveMask;
|
getline(strstream, buff, ',');
|
||||||
|
peds->setModelID(std::atoi(buff.c_str()));
|
||||||
|
|
||||||
getline(strstream, id, ',');
|
getline(strstream, peds->name, ',');
|
||||||
getline(strstream, peds->modelName, ',');
|
getline(strstream, peds->textureslot, ',');
|
||||||
getline(strstream, peds->textureName, ',');
|
|
||||||
getline(strstream, peds->type, ',');
|
|
||||||
getline(strstream, peds->behaviour, ',');
|
|
||||||
getline(strstream, peds->animGroup, ',');
|
|
||||||
getline(strstream, driveMask, ',');
|
|
||||||
|
|
||||||
peds->ID = atoi(id.c_str());
|
getline(strstream, buff, ',');
|
||||||
peds->driveMask = atoi(driveMask.c_str());
|
peds->pedtype_ = PedModelInfo::findPedType(buff);
|
||||||
|
|
||||||
objects.insert({peds->ID, peds});
|
getline(strstream, peds->behaviour_, ',');
|
||||||
|
getline(strstream, peds->animgroup_, ',');
|
||||||
|
|
||||||
|
getline(strstream, buff, ',');
|
||||||
|
peds->carsmask_ = std::atoi(buff.c_str());
|
||||||
|
|
||||||
|
objects.emplace(peds->id(), std::move(peds));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PATH: {
|
case PATH: {
|
||||||
@ -253,25 +232,22 @@ bool LoaderIDE::load(const std::string &filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto &object = objects[path.ID];
|
auto &object = objects[path.ID];
|
||||||
auto instance =
|
auto simple = dynamic_cast<SimpleModelInfo*>(object.get());
|
||||||
std::dynamic_pointer_cast<ObjectData>(object);
|
simple->paths.push_back(path);
|
||||||
instance->paths.push_back(path);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HIER: {
|
case HIER: {
|
||||||
std::shared_ptr<CutsceneObjectData> cut(
|
auto hier =
|
||||||
new CutsceneObjectData);
|
std::unique_ptr<ClumpModelInfo>(new ClumpModelInfo);
|
||||||
|
|
||||||
std::string id;
|
getline(strstream, buff, ',');
|
||||||
|
hier->setModelID(std::atoi(buff.c_str()));
|
||||||
|
|
||||||
getline(strstream, id, ',');
|
getline(strstream, hier->name, ',');
|
||||||
getline(strstream, cut->modelName, ',');
|
getline(strstream, hier->textureslot, ',');
|
||||||
getline(strstream, cut->textureName, ',');
|
|
||||||
|
|
||||||
cut->ID = atoi(id.c_str());
|
objects.emplace(hier->id(), std::move(hier));
|
||||||
|
|
||||||
objects.insert({cut->ID, cut});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
#pragma once
|
#ifndef RWENGINE_LOADERIDE_HPP
|
||||||
#ifndef _LOADERIDE_HPP_
|
#define RWENGINE_LOADERIDE_HPP
|
||||||
#define _LOADERIDE_HPP_
|
|
||||||
|
|
||||||
#include <data/ObjectData.hpp>
|
#include <data/ModelData.hpp>
|
||||||
#include <data/PathData.hpp>
|
#include <data/PathData.hpp>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -28,13 +27,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief objects loaded during the call to load()
|
* @brief objects loaded during the call to load()
|
||||||
*/
|
*/
|
||||||
std::map<ObjectID, ObjectInformationPtr> objects;
|
std::map<ModelID, std::unique_ptr<BaseModelInfo>> objects;
|
||||||
|
|
||||||
/*std::vector<std::shared_ptr<ObjectData>> OBJSs;
|
|
||||||
std::vector<std::shared_ptr<VehicleData>> CARSs;
|
|
||||||
std::vector<std::shared_ptr<CharacterData>> PEDSs;
|
|
||||||
std::vector<std::shared_ptr<CutsceneObjectData>> HIERs;
|
|
||||||
std::vector<std::shared_ptr<PathData>> PATHs;*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -14,9 +14,9 @@ static glm::vec3 enter_offset(0.81756252f, 0.34800607f, -0.486281008f);
|
|||||||
const float CharacterObject::DefaultJumpSpeed = 2.f;
|
const float CharacterObject::DefaultJumpSpeed = 2.f;
|
||||||
|
|
||||||
CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos,
|
CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos,
|
||||||
const glm::quat& rot, const ModelRef& model,
|
const glm::quat& rot,
|
||||||
std::shared_ptr<CharacterData> data)
|
BaseModelInfo *modelinfo)
|
||||||
: GameObject(engine, pos, rot, model)
|
: GameObject(engine, pos, rot, modelinfo)
|
||||||
, currentState({})
|
, currentState({})
|
||||||
, currentVehicle(nullptr)
|
, currentVehicle(nullptr)
|
||||||
, currentSeat(0)
|
, currentSeat(0)
|
||||||
@ -24,7 +24,6 @@ CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos,
|
|||||||
, jumped(false)
|
, jumped(false)
|
||||||
, jumpSpeed(DefaultJumpSpeed)
|
, jumpSpeed(DefaultJumpSpeed)
|
||||||
, motionBlockedByActivity(false)
|
, motionBlockedByActivity(false)
|
||||||
, ped(data)
|
|
||||||
, physCharacter(nullptr)
|
, physCharacter(nullptr)
|
||||||
, physObject(nullptr)
|
, physObject(nullptr)
|
||||||
, physShape(nullptr)
|
, physShape(nullptr)
|
||||||
@ -66,9 +65,11 @@ CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos,
|
|||||||
animations.kd_front = engine->data->animations["kd_front"];
|
animations.kd_front = engine->data->animations["kd_front"];
|
||||||
animations.ko_shot_front = engine->data->animations["ko_shot_front"];
|
animations.ko_shot_front = engine->data->animations["ko_shot_front"];
|
||||||
|
|
||||||
if (model) {
|
auto info = getModelInfo<PedModelInfo>();
|
||||||
|
if (info->getModel()) {
|
||||||
|
setModel(info->getModel());
|
||||||
skeleton = new Skeleton;
|
skeleton = new Skeleton;
|
||||||
animator = new Animator(model->resource, skeleton);
|
animator = new Animator(getModel(), skeleton);
|
||||||
|
|
||||||
createActor();
|
createActor();
|
||||||
}
|
}
|
||||||
@ -87,7 +88,7 @@ void CharacterObject::createActor(const glm::vec2& size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't create anything without a valid model.
|
// Don't create anything without a valid model.
|
||||||
if (model) {
|
if (getModel()) {
|
||||||
btTransform tf;
|
btTransform tf;
|
||||||
tf.setIdentity();
|
tf.setIdentity();
|
||||||
tf.setOrigin(btVector3(position.x, position.y, position.z));
|
tf.setOrigin(btVector3(position.x, position.y, position.z));
|
||||||
@ -205,8 +206,8 @@ glm::vec3 CharacterObject::updateMovementAnimation(float dt) {
|
|||||||
|
|
||||||
// If we have to, interrogate the movement animation
|
// If we have to, interrogate the movement animation
|
||||||
if (movementAnimation != animations.idle) {
|
if (movementAnimation != animations.idle) {
|
||||||
if (!model->resource->frames[0]->getChildren().empty()) {
|
if (!getModel()->frames[0]->getChildren().empty()) {
|
||||||
ModelFrame* root = model->resource->frames[0]->getChildren()[0];
|
ModelFrame* root = getModel()->frames[0]->getChildren()[0];
|
||||||
auto it = movementAnimation->bones.find(root->getName());
|
auto it = movementAnimation->bones.find(root->getName());
|
||||||
if (it != movementAnimation->bones.end()) {
|
if (it != movementAnimation->bones.end()) {
|
||||||
AnimationBone* rootBone = it->second;
|
AnimationBone* rootBone = it->second;
|
||||||
@ -266,22 +267,20 @@ void CharacterObject::changeCharacterModel(const std::string& name) {
|
|||||||
std::transform(modelName.begin(), modelName.end(), modelName.begin(),
|
std::transform(modelName.begin(), modelName.end(), modelName.begin(),
|
||||||
::tolower);
|
::tolower);
|
||||||
|
|
||||||
engine->data->loadDFF(modelName + ".dff");
|
/// @todo don't model leak here
|
||||||
engine->data->loadTXD(modelName + ".txd");
|
|
||||||
|
|
||||||
auto& models = engine->data->models;
|
engine->data->loadTXD(modelName + ".txd");
|
||||||
auto mfind = models.find(modelName);
|
auto newmodel = engine->data->loadClump(modelName + ".dff");
|
||||||
if (mfind != models.end()) {
|
|
||||||
model = mfind->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skeleton) {
|
if (skeleton) {
|
||||||
delete animator;
|
delete animator;
|
||||||
delete skeleton;
|
delete skeleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setModel(newmodel);
|
||||||
|
|
||||||
skeleton = new Skeleton;
|
skeleton = new Skeleton;
|
||||||
animator = new Animator(model->resource, skeleton);
|
animator = new Animator(getModel(), skeleton);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterObject::updateCharacter(float dt) {
|
void CharacterObject::updateCharacter(float dt) {
|
||||||
|
@ -125,8 +125,6 @@ private:
|
|||||||
public:
|
public:
|
||||||
static const float DefaultJumpSpeed;
|
static const float DefaultJumpSpeed;
|
||||||
|
|
||||||
std::shared_ptr<CharacterData> ped;
|
|
||||||
|
|
||||||
btKinematicCharacterController* physCharacter;
|
btKinematicCharacterController* physCharacter;
|
||||||
btPairCachingGhostObject* physObject;
|
btPairCachingGhostObject* physObject;
|
||||||
btCapsuleShapeZ* physShape;
|
btCapsuleShapeZ* physShape;
|
||||||
@ -142,8 +140,7 @@ public:
|
|||||||
* @param ped PEDS_t struct to use.
|
* @param ped PEDS_t struct to use.
|
||||||
*/
|
*/
|
||||||
CharacterObject(GameWorld* engine, const glm::vec3& pos,
|
CharacterObject(GameWorld* engine, const glm::vec3& pos,
|
||||||
const glm::quat& rot, const ModelRef& model,
|
const glm::quat& rot, BaseModelInfo* modelinfo);
|
||||||
std::shared_ptr<CharacterData> data);
|
|
||||||
|
|
||||||
~CharacterObject();
|
~CharacterObject();
|
||||||
|
|
||||||
|
@ -3,10 +3,19 @@
|
|||||||
#include <objects/CutsceneObject.hpp>
|
#include <objects/CutsceneObject.hpp>
|
||||||
|
|
||||||
CutsceneObject::CutsceneObject(GameWorld *engine, const glm::vec3 &pos,
|
CutsceneObject::CutsceneObject(GameWorld *engine, const glm::vec3 &pos,
|
||||||
const glm::quat &rot, const ModelRef &model)
|
const glm::quat &rot, Model *model,
|
||||||
: GameObject(engine, pos, rot, model), _parent(nullptr), _bone(nullptr) {
|
BaseModelInfo *modelinfo)
|
||||||
|
: GameObject(engine, pos, rot, modelinfo)
|
||||||
|
, _parent(nullptr)
|
||||||
|
, _bone(nullptr) {
|
||||||
|
if (model) {
|
||||||
|
setModel(model);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setModel(getModelInfo<ClumpModelInfo>()->getModel());
|
||||||
|
}
|
||||||
skeleton = new Skeleton;
|
skeleton = new Skeleton;
|
||||||
animator = new Animator(model->resource, skeleton);
|
animator = new Animator(getModel(), skeleton);
|
||||||
}
|
}
|
||||||
|
|
||||||
CutsceneObject::~CutsceneObject() {
|
CutsceneObject::~CutsceneObject() {
|
||||||
|
@ -12,7 +12,8 @@ class CutsceneObject : public GameObject {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
CutsceneObject(GameWorld* engine, const glm::vec3& pos,
|
CutsceneObject(GameWorld* engine, const glm::vec3& pos,
|
||||||
const glm::quat& rot, const ModelRef& model);
|
const glm::quat& rot, Model* model,
|
||||||
|
BaseModelInfo* modelinfo);
|
||||||
~CutsceneObject();
|
~CutsceneObject();
|
||||||
|
|
||||||
Type type() {
|
Type type() {
|
||||||
|
@ -12,6 +12,10 @@ GameObject::~GameObject() {
|
|||||||
if (skeleton) {
|
if (skeleton) {
|
||||||
delete skeleton;
|
delete skeleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (modelinfo_) {
|
||||||
|
modelinfo_->removeReference();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameObject::setPosition(const glm::vec3& pos) {
|
void GameObject::setPosition(const glm::vec3& pos) {
|
||||||
|
@ -28,13 +28,22 @@ class GameObject {
|
|||||||
glm::quat _lastRotation;
|
glm::quat _lastRotation;
|
||||||
GameObjectID objectID;
|
GameObjectID objectID;
|
||||||
|
|
||||||
|
BaseModelInfo* modelinfo_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model used for rendering
|
||||||
|
*/
|
||||||
|
Model* model_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void changeModelInfo(BaseModelInfo* next) {
|
||||||
|
modelinfo_ = next;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
glm::quat rotation;
|
glm::quat rotation;
|
||||||
|
|
||||||
/// Reference to Model data
|
|
||||||
ModelRef model;
|
|
||||||
|
|
||||||
GameWorld* engine;
|
GameWorld* engine;
|
||||||
|
|
||||||
Animator* animator; /// Object's animator.
|
Animator* animator; /// Object's animator.
|
||||||
@ -53,13 +62,14 @@ public:
|
|||||||
bool visible;
|
bool visible;
|
||||||
|
|
||||||
GameObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot,
|
GameObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot,
|
||||||
ModelRef model)
|
BaseModelInfo* modelinfo)
|
||||||
: _lastPosition(pos)
|
: _lastPosition(pos)
|
||||||
, _lastRotation(rot)
|
, _lastRotation(rot)
|
||||||
, objectID(0)
|
, objectID(0)
|
||||||
|
, modelinfo_(modelinfo)
|
||||||
|
, model_(nullptr)
|
||||||
, position(pos)
|
, position(pos)
|
||||||
, rotation(rot)
|
, rotation(rot)
|
||||||
, model(model)
|
|
||||||
, engine(engine)
|
, engine(engine)
|
||||||
, animator(nullptr)
|
, animator(nullptr)
|
||||||
, skeleton(nullptr)
|
, skeleton(nullptr)
|
||||||
@ -67,6 +77,9 @@ public:
|
|||||||
, _lastHeight(std::numeric_limits<float>::max())
|
, _lastHeight(std::numeric_limits<float>::max())
|
||||||
, visible(true)
|
, visible(true)
|
||||||
, lifetime(GameObject::UnknownLifetime) {
|
, lifetime(GameObject::UnknownLifetime) {
|
||||||
|
if (modelinfo_) {
|
||||||
|
modelinfo_->addReference();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~GameObject();
|
virtual ~GameObject();
|
||||||
@ -85,6 +98,25 @@ public:
|
|||||||
return getGameObjectID();
|
return getGameObjectID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T* getModelInfo() const {
|
||||||
|
return static_cast<T*>(modelinfo_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The model used in rendering
|
||||||
|
*/
|
||||||
|
Model* getModel() const {
|
||||||
|
return model_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the current model, used for re-dressing chars
|
||||||
|
*/
|
||||||
|
void setModel(Model* model) {
|
||||||
|
model_ = model;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enumeration of possible object types.
|
* @brief Enumeration of possible object types.
|
||||||
*/
|
*/
|
||||||
|
@ -6,24 +6,25 @@
|
|||||||
#include <objects/InstanceObject.hpp>
|
#include <objects/InstanceObject.hpp>
|
||||||
|
|
||||||
InstanceObject::InstanceObject(GameWorld* engine, const glm::vec3& pos,
|
InstanceObject::InstanceObject(GameWorld* engine, const glm::vec3& pos,
|
||||||
const glm::quat& rot, const ModelRef& model,
|
const glm::quat& rot, const glm::vec3& scale,
|
||||||
const glm::vec3& scale,
|
BaseModelInfo* modelinfo, InstanceObject* lod,
|
||||||
std::shared_ptr<ObjectData> obj,
|
|
||||||
InstanceObject* lod,
|
|
||||||
std::shared_ptr<DynamicObjectData> dyn)
|
std::shared_ptr<DynamicObjectData> dyn)
|
||||||
: GameObject(engine, pos, rot, model)
|
: GameObject(engine, pos, rot, modelinfo)
|
||||||
, health(100.f)
|
, health(100.f)
|
||||||
, scale(scale)
|
, scale(scale)
|
||||||
, body(nullptr)
|
, body(nullptr)
|
||||||
, object(obj)
|
|
||||||
, LODinstance(lod)
|
, LODinstance(lod)
|
||||||
, dynamics(dyn)
|
, dynamics(dyn)
|
||||||
, _enablePhysics(false) {
|
, _enablePhysics(false) {
|
||||||
if (obj) {
|
if (modelinfo) {
|
||||||
changeModel(obj);
|
changeModel(modelinfo);
|
||||||
|
|
||||||
for (auto& path : obj->paths) {
|
/// @todo store path information properly
|
||||||
engine->aigraph.createPathNodes(position, rot, path);
|
if (modelinfo->type() == ModelDataType::SimpleInfo) {
|
||||||
|
auto simpledata = static_cast<SimpleModelInfo*>(modelinfo);
|
||||||
|
for (auto& path : simpledata->paths) {
|
||||||
|
engine->aigraph.createPathNodes(position, rot, path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,18 +121,24 @@ void InstanceObject::tick(float dt) {
|
|||||||
if (animator) animator->tick(dt);
|
if (animator) animator->tick(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceObject::changeModel(std::shared_ptr<ObjectData> incoming) {
|
void InstanceObject::changeModel(BaseModelInfo* incoming) {
|
||||||
if (body) {
|
if (body) {
|
||||||
delete body;
|
delete body;
|
||||||
body = nullptr;
|
body = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
object = incoming;
|
|
||||||
|
|
||||||
if (incoming) {
|
if (incoming) {
|
||||||
|
if (!incoming->isLoaded()) {
|
||||||
|
engine->data->loadModel(incoming->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
changeModelInfo(incoming);
|
||||||
|
/// @todo this should only be temporary
|
||||||
|
setModel(getModelInfo<SimpleModelInfo>()->getModel());
|
||||||
|
|
||||||
auto bod = new CollisionInstance;
|
auto bod = new CollisionInstance;
|
||||||
|
|
||||||
if (bod->createPhysicsBody(this, object->modelName, dynamics.get())) {
|
if (bod->createPhysicsBody(this, incoming->name, dynamics.get())) {
|
||||||
bod->getBulletBody()->setActivationState(ISLAND_SLEEPING);
|
bod->getBulletBody()->setActivationState(ISLAND_SLEEPING);
|
||||||
body = bod;
|
body = bod;
|
||||||
}
|
}
|
||||||
|
@ -17,15 +17,14 @@ class InstanceObject : public GameObject {
|
|||||||
public:
|
public:
|
||||||
glm::vec3 scale;
|
glm::vec3 scale;
|
||||||
CollisionInstance* body;
|
CollisionInstance* body;
|
||||||
std::shared_ptr<ObjectData> object;
|
|
||||||
InstanceObject* LODinstance;
|
InstanceObject* LODinstance;
|
||||||
std::shared_ptr<DynamicObjectData> dynamics;
|
std::shared_ptr<DynamicObjectData> dynamics;
|
||||||
bool _enablePhysics;
|
bool _enablePhysics;
|
||||||
|
|
||||||
InstanceObject(GameWorld* engine, const glm::vec3& pos,
|
InstanceObject(GameWorld* engine, const glm::vec3& pos,
|
||||||
const glm::quat& rot, const ModelRef& model,
|
const glm::quat& rot, const glm::vec3& scale,
|
||||||
const glm::vec3& scale, std::shared_ptr<ObjectData> obj,
|
BaseModelInfo* modelinfo, InstanceObject* lod,
|
||||||
InstanceObject* lod, std::shared_ptr<DynamicObjectData> dyn);
|
std::shared_ptr<DynamicObjectData> dyn);
|
||||||
~InstanceObject();
|
~InstanceObject();
|
||||||
|
|
||||||
Type type() {
|
Type type() {
|
||||||
@ -34,7 +33,7 @@ public:
|
|||||||
|
|
||||||
void tick(float dt);
|
void tick(float dt);
|
||||||
|
|
||||||
void changeModel(std::shared_ptr<ObjectData> incoming);
|
void changeModel(BaseModelInfo* incoming);
|
||||||
|
|
||||||
virtual void setRotation(const glm::quat& r);
|
virtual void setRotation(const glm::quat& r);
|
||||||
|
|
||||||
|
@ -5,8 +5,9 @@
|
|||||||
#include <rw/defines.hpp>
|
#include <rw/defines.hpp>
|
||||||
|
|
||||||
ItemPickup::ItemPickup(GameWorld *world, const glm::vec3 &position,
|
ItemPickup::ItemPickup(GameWorld *world, const glm::vec3 &position,
|
||||||
PickupType type, InventoryItem *item)
|
BaseModelInfo *modelinfo, PickupType type,
|
||||||
: PickupObject(world, position, item->getModelID(), type), item(item) {
|
InventoryItem *item)
|
||||||
|
: PickupObject(world, position, modelinfo, type), item(item) {
|
||||||
RW_CHECK(item != nullptr, "Pickup created with null item");
|
RW_CHECK(item != nullptr, "Pickup created with null item");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ class ItemPickup : public PickupObject {
|
|||||||
InventoryItem* item;
|
InventoryItem* item;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ItemPickup(GameWorld* world, const glm::vec3& position, PickupType type,
|
ItemPickup(GameWorld* world, const glm::vec3& position, BaseModelInfo *modelinfo, PickupType type,
|
||||||
InventoryItem* item);
|
InventoryItem* item);
|
||||||
|
|
||||||
bool onCharacterTouch(CharacterObject* character);
|
bool onCharacterTouch(CharacterObject* character);
|
||||||
|
@ -59,13 +59,12 @@ uint32_t PickupObject::behaviourFlags(PickupType type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PickupObject::PickupObject(GameWorld* world, const glm::vec3& position,
|
PickupObject::PickupObject(GameWorld* world, const glm::vec3& position,
|
||||||
int modelID, PickupType type)
|
BaseModelInfo* modelinfo, PickupType type)
|
||||||
: GameObject(world, position, glm::quat(), nullptr)
|
: GameObject(world, position, glm::quat(), modelinfo)
|
||||||
, m_ghost(nullptr)
|
, m_ghost(nullptr)
|
||||||
, m_shape(nullptr)
|
, m_shape(nullptr)
|
||||||
, m_enabled(false)
|
, m_enabled(false)
|
||||||
, m_collected(false)
|
, m_collected(false)
|
||||||
, m_model(modelID)
|
|
||||||
, m_type(type) {
|
, m_type(type) {
|
||||||
btTransform tf;
|
btTransform tf;
|
||||||
tf.setIdentity();
|
tf.setIdentity();
|
||||||
|
@ -37,15 +37,11 @@ public:
|
|||||||
static float respawnTime(PickupType type);
|
static float respawnTime(PickupType type);
|
||||||
static uint32_t behaviourFlags(PickupType type);
|
static uint32_t behaviourFlags(PickupType type);
|
||||||
|
|
||||||
PickupObject(GameWorld* world, const glm::vec3& position, int modelID,
|
PickupObject(GameWorld* world, const glm::vec3& position, BaseModelInfo *modelinfo,
|
||||||
PickupType type);
|
PickupType type);
|
||||||
|
|
||||||
~PickupObject();
|
~PickupObject();
|
||||||
|
|
||||||
int getModelID() const {
|
|
||||||
return m_model;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type type() {
|
Type type() {
|
||||||
return Pickup;
|
return Pickup;
|
||||||
}
|
}
|
||||||
@ -76,7 +72,6 @@ private:
|
|||||||
bool m_enabled;
|
bool m_enabled;
|
||||||
float m_enableTimer;
|
float m_enableTimer;
|
||||||
bool m_collected;
|
bool m_collected;
|
||||||
int m_model;
|
|
||||||
VisualFX* m_corona;
|
VisualFX* m_corona;
|
||||||
|
|
||||||
PickupType m_type;
|
PickupType m_type;
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct VehicleData;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stores data loaded from handling.cfg
|
* @brief Stores data loaded from handling.cfg
|
||||||
*/
|
*/
|
||||||
|
@ -83,15 +83,14 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos,
|
VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos,
|
||||||
const glm::quat& rot, const ModelRef& model,
|
const glm::quat& rot, BaseModelInfo* modelinfo,
|
||||||
VehicleDataHandle data, VehicleInfoHandle info,
|
VehicleInfoHandle info, const glm::u8vec3& prim,
|
||||||
const glm::u8vec3& prim, const glm::u8vec3& sec)
|
const glm::u8vec3& sec)
|
||||||
: GameObject(engine, pos, rot, model)
|
: GameObject(engine, pos, rot, modelinfo)
|
||||||
, steerAngle(0.f)
|
, steerAngle(0.f)
|
||||||
, throttle(0.f)
|
, throttle(0.f)
|
||||||
, brake(0.f)
|
, brake(0.f)
|
||||||
, handbrake(true)
|
, handbrake(true)
|
||||||
, vehicle(data)
|
|
||||||
, info(info)
|
, info(info)
|
||||||
, colourPrimary(prim)
|
, colourPrimary(prim)
|
||||||
, colourSecondary(sec)
|
, colourSecondary(sec)
|
||||||
@ -99,7 +98,7 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos,
|
|||||||
, physRaycaster(nullptr)
|
, physRaycaster(nullptr)
|
||||||
, physVehicle(nullptr) {
|
, physVehicle(nullptr) {
|
||||||
collision = new CollisionInstance;
|
collision = new CollisionInstance;
|
||||||
if (collision->createPhysicsBody(this, data->modelName, nullptr,
|
if (collision->createPhysicsBody(this, modelinfo->name, nullptr,
|
||||||
&info->handling)) {
|
&info->handling)) {
|
||||||
physRaycaster = new VehicleRaycaster(this, engine->dynamicsWorld);
|
physRaycaster = new VehicleRaycaster(this, engine->dynamicsWorld);
|
||||||
btRaycastVehicle::btVehicleTuning tuning;
|
btRaycastVehicle::btVehicleTuning tuning;
|
||||||
@ -127,7 +126,7 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos,
|
|||||||
bool front = connection.y() > 0;
|
bool front = connection.y() > 0;
|
||||||
btWheelInfo& wi = physVehicle->addWheel(
|
btWheelInfo& wi = physVehicle->addWheel(
|
||||||
connection, btVector3(0.f, 0.f, -1.f), btVector3(1.f, 0.f, 0.f),
|
connection, btVector3(0.f, 0.f, -1.f), btVector3(1.f, 0.f, 0.f),
|
||||||
restLength, data->wheelScale / 2.f, tuning, front);
|
restLength, getVehicle()->wheelscale_ / 2.f, tuning, front);
|
||||||
wi.m_suspensionRestLength1 = restLength;
|
wi.m_suspensionRestLength1 = restLength;
|
||||||
wi.m_raycastInfo.m_suspensionLength = 0.f;
|
wi.m_raycastInfo.m_suspensionLength = 0.f;
|
||||||
|
|
||||||
@ -153,7 +152,9 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos,
|
|||||||
// Hide all LOD and damage frames.
|
// Hide all LOD and damage frames.
|
||||||
skeleton = new Skeleton;
|
skeleton = new Skeleton;
|
||||||
|
|
||||||
for (ModelFrame* frame : model->resource->frames) {
|
setModel(getVehicle()->getModel());
|
||||||
|
|
||||||
|
for (ModelFrame* frame : getModel()->frames) {
|
||||||
auto& name = frame->getName();
|
auto& name = frame->getName();
|
||||||
bool isDam = name.find("_dam") != name.npos;
|
bool isDam = name.find("_dam") != name.npos;
|
||||||
bool isLod = name.find("lo") != name.npos;
|
bool isLod = name.find("lo") != name.npos;
|
||||||
@ -282,7 +283,7 @@ void VehicleObject::tickPhysics(float dt) {
|
|||||||
seat.second->updateTransform(passPosition, getRotation());
|
seat.second->updateTransform(passPosition, getRotation());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vehicle->type == VehicleData::BOAT) {
|
if (getVehicle()->vehicletype_ == VehicleModelInfo::BOAT) {
|
||||||
if (isInWater()) {
|
if (isInWater()) {
|
||||||
float sign = std::signbit(steerAngle) ? -1.f : 1.f;
|
float sign = std::signbit(steerAngle) ? -1.f : 1.f;
|
||||||
float steer =
|
float steer =
|
||||||
@ -356,6 +357,7 @@ void VehicleObject::tickPhysics(float dt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto isBoat = getVehicle()->vehicletype_ == VehicleModelInfo::BOAT;
|
||||||
if (inWater) {
|
if (inWater) {
|
||||||
// Ensure that vehicles don't fall asleep at the top of a wave.
|
// Ensure that vehicles don't fall asleep at the top of a wave.
|
||||||
if (!collision->getBulletBody()->isActive()) {
|
if (!collision->getBulletBody()->isActive()) {
|
||||||
@ -367,15 +369,13 @@ void VehicleObject::tickPhysics(float dt) {
|
|||||||
float oZ = 0.f;
|
float oZ = 0.f;
|
||||||
oZ = -bbZ / 2.f + (bbZ * (info->handling.percentSubmerged / 120.f));
|
oZ = -bbZ / 2.f + (bbZ * (info->handling.percentSubmerged / 120.f));
|
||||||
|
|
||||||
if (vehicle->type != VehicleData::BOAT) {
|
if (isBoat) {
|
||||||
|
oZ = 0.f;
|
||||||
|
} else {
|
||||||
// Damper motion
|
// Damper motion
|
||||||
collision->getBulletBody()->setDamping(0.95f, 0.9f);
|
collision->getBulletBody()->setDamping(0.95f, 0.9f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vehicle->type == VehicleData::BOAT) {
|
|
||||||
oZ = 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Boats, Buoyancy offset is affected by the orientation of the
|
// Boats, Buoyancy offset is affected by the orientation of the
|
||||||
// chassis.
|
// chassis.
|
||||||
// Vehicles, it isn't.
|
// Vehicles, it isn't.
|
||||||
@ -399,7 +399,7 @@ void VehicleObject::tickPhysics(float dt) {
|
|||||||
applyWaterFloat(vRt);
|
applyWaterFloat(vRt);
|
||||||
applyWaterFloat(vLeft);
|
applyWaterFloat(vLeft);
|
||||||
} else {
|
} else {
|
||||||
if (vehicle->type == VehicleData::BOAT) {
|
if (isBoat) {
|
||||||
collision->getBulletBody()->setDamping(0.1f, 0.8f);
|
collision->getBulletBody()->setDamping(0.1f, 0.8f);
|
||||||
} else {
|
} else {
|
||||||
collision->getBulletBody()->setDamping(0.05f, 0.0f);
|
collision->getBulletBody()->setDamping(0.05f, 0.0f);
|
||||||
@ -556,7 +556,7 @@ bool VehicleObject::takeDamage(const GameObject::DamageInfo& dmg) {
|
|||||||
|
|
||||||
if (skeleton->getData(p->normal->getIndex()).enabled) {
|
if (skeleton->getData(p->normal->getIndex()).enabled) {
|
||||||
auto& geom =
|
auto& geom =
|
||||||
model->resource->geometries[p->normal->getGeometries()[0]];
|
getModel()->geometries[p->normal->getGeometries()[0]];
|
||||||
auto pp =
|
auto pp =
|
||||||
p->normal->getMatrix() * glm::vec4(0.f, 0.f, 0.f, 1.f);
|
p->normal->getMatrix() * glm::vec4(0.f, 0.f, 0.f, 1.f);
|
||||||
float td = glm::distance(
|
float td = glm::distance(
|
||||||
@ -680,7 +680,7 @@ void VehicleObject::createObjectHinge(Part* part) {
|
|||||||
|
|
||||||
if (okframe->getGeometries().size() == 0) return;
|
if (okframe->getGeometries().size() == 0) return;
|
||||||
|
|
||||||
auto& geom = model->resource->geometries[okframe->getGeometries()[0]];
|
auto& geom = getModel()->geometries[okframe->getGeometries()[0]];
|
||||||
auto gbounds = geom->geometryBounds;
|
auto gbounds = geom->geometryBounds;
|
||||||
|
|
||||||
if (fn.find("door") != fn.npos) {
|
if (fn.find("door") != fn.npos) {
|
||||||
|
@ -24,7 +24,6 @@ private:
|
|||||||
bool handbrake;
|
bool handbrake;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VehicleDataHandle vehicle;
|
|
||||||
VehicleInfoHandle info;
|
VehicleInfoHandle info;
|
||||||
glm::u8vec3 colourPrimary;
|
glm::u8vec3 colourPrimary;
|
||||||
glm::u8vec3 colourSecondary;
|
glm::u8vec3 colourSecondary;
|
||||||
@ -50,9 +49,8 @@ public:
|
|||||||
std::map<std::string, Part> dynamicParts;
|
std::map<std::string, Part> dynamicParts;
|
||||||
|
|
||||||
VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot,
|
VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot,
|
||||||
const ModelRef& model, VehicleDataHandle data,
|
BaseModelInfo* modelinfo, VehicleInfoHandle info,
|
||||||
VehicleInfoHandle info, const glm::u8vec3& prim,
|
const glm::u8vec3& prim, const glm::u8vec3& sec);
|
||||||
const glm::u8vec3& sec);
|
|
||||||
|
|
||||||
virtual ~VehicleObject();
|
virtual ~VehicleObject();
|
||||||
|
|
||||||
@ -60,6 +58,10 @@ public:
|
|||||||
|
|
||||||
void setRotation(const glm::quat& orientation);
|
void setRotation(const glm::quat& orientation);
|
||||||
|
|
||||||
|
VehicleModelInfo* getVehicle() const {
|
||||||
|
return getModelInfo<VehicleModelInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
Type type() {
|
Type type() {
|
||||||
return Vehicle;
|
return Vehicle;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#include <objects/VehicleObject.hpp>
|
#include <objects/VehicleObject.hpp>
|
||||||
|
|
||||||
#include <ai/CharacterController.hpp>
|
#include <ai/CharacterController.hpp>
|
||||||
#include <data/ObjectData.hpp>
|
#include <data/ModelData.hpp>
|
||||||
#include <items/InventoryItem.hpp>
|
#include <items/InventoryItem.hpp>
|
||||||
|
|
||||||
#include <data/CutsceneData.hpp>
|
#include <data/CutsceneData.hpp>
|
||||||
@ -210,40 +210,6 @@ GameRenderer::GameRenderer(Logger* log, GameData* _data)
|
|||||||
ssRectSize = glGetUniformLocation(ssRectProgram, "size");
|
ssRectSize = glGetUniformLocation(ssRectProgram, "size");
|
||||||
ssRectOffset = glGetUniformLocation(ssRectProgram, "offset");
|
ssRectOffset = glGetUniformLocation(ssRectProgram, "offset");
|
||||||
|
|
||||||
const static int cylsegments = 16;
|
|
||||||
std::vector<Model::GeometryVertex> cylverts;
|
|
||||||
for (int s = 0; s < cylsegments; ++s) {
|
|
||||||
float theta = (2.f * glm::pi<float>() / cylsegments) * (s + 0);
|
|
||||||
float gamma = (2.f * glm::pi<float>() / cylsegments) * (s + 1);
|
|
||||||
glm::vec2 p0(glm::sin(theta), glm::cos(theta));
|
|
||||||
glm::vec2 p1(glm::sin(gamma), glm::cos(gamma));
|
|
||||||
|
|
||||||
p0 *= 0.5f;
|
|
||||||
p1 *= 0.5f;
|
|
||||||
|
|
||||||
cylverts.push_back({glm::vec3(p0, 2.f), glm::vec3(),
|
|
||||||
glm::vec2(0.45f, 0.6f),
|
|
||||||
glm::u8vec4(255, 255, 255, 50)});
|
|
||||||
cylverts.push_back({glm::vec3(p0, -1.f), glm::vec3(),
|
|
||||||
glm::vec2(0.45f, 0.4f),
|
|
||||||
glm::u8vec4(255, 255, 255, 150)});
|
|
||||||
cylverts.push_back({glm::vec3(p1, 2.f), glm::vec3(),
|
|
||||||
glm::vec2(0.55f, 0.6f),
|
|
||||||
glm::u8vec4(255, 255, 255, 50)});
|
|
||||||
|
|
||||||
cylverts.push_back({glm::vec3(p0, -1.f), glm::vec3(),
|
|
||||||
glm::vec2(0.45f, 0.4f),
|
|
||||||
glm::u8vec4(255, 255, 255, 150)});
|
|
||||||
cylverts.push_back({glm::vec3(p1, -1.f), glm::vec3(),
|
|
||||||
glm::vec2(0.55f, 0.4f),
|
|
||||||
glm::u8vec4(255, 255, 255, 150)});
|
|
||||||
cylverts.push_back({glm::vec3(p1, 2.f), glm::vec3(),
|
|
||||||
glm::vec2(0.55f, 0.6f),
|
|
||||||
glm::u8vec4(255, 255, 255, 50)});
|
|
||||||
}
|
|
||||||
cylinderGeometry.uploadVertices<Model::GeometryVertex>(cylverts);
|
|
||||||
cylinderBuffer.addGeometry(&cylinderGeometry);
|
|
||||||
cylinderBuffer.setFaceType(GL_TRIANGLES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GameRenderer::~GameRenderer() {
|
GameRenderer::~GameRenderer() {
|
||||||
@ -330,7 +296,7 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera& camera,
|
|||||||
// This is sequential at the moment, it should be easy to make it
|
// This is sequential at the moment, it should be easy to make it
|
||||||
// run in parallel with a good threading system.
|
// run in parallel with a good threading system.
|
||||||
RenderList renderList;
|
RenderList renderList;
|
||||||
// Naive optimisation, assume 10% hitrate
|
// Naive optimisation, assume 50% hitrate
|
||||||
renderList.reserve(world->allObjects.size() * 0.5f);
|
renderList.reserve(world->allObjects.size() * 0.5f);
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("Build");
|
RW_PROFILE_BEGIN("Build");
|
||||||
@ -343,6 +309,48 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera& camera,
|
|||||||
for (auto object : world->allObjects) {
|
for (auto object : world->allObjects) {
|
||||||
objectRenderer.buildRenderList(object, renderList);
|
objectRenderer.buildRenderList(object, renderList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Area indicators
|
||||||
|
auto sphereModel = getSpecialModel(ZoneCylinderA);
|
||||||
|
for (auto& i : world->getAreaIndicators()) {
|
||||||
|
glm::mat4 m(1.f);
|
||||||
|
m = glm::translate(m, i.position);
|
||||||
|
m = glm::scale(
|
||||||
|
m, glm::vec3(i.radius +
|
||||||
|
0.15f * glm::sin(_renderWorld->getGameTime() * 5.f)));
|
||||||
|
|
||||||
|
objectRenderer.renderFrame(sphereModel, sphereModel->frames[0], m,
|
||||||
|
nullptr, 1.f, renderList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render arrows above anything that isn't radar only (or hidden)
|
||||||
|
auto arrowModel = getSpecialModel(Arrow);
|
||||||
|
for (auto& blip : world->state->radarBlips) {
|
||||||
|
auto dm = blip.second.display;
|
||||||
|
if (dm == BlipData::Hide || dm == BlipData::RadarOnly) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 model;
|
||||||
|
|
||||||
|
if (blip.second.target > 0) {
|
||||||
|
auto object = world->getBlipTarget(blip.second);
|
||||||
|
if (object) {
|
||||||
|
model = object->getTimeAdjustedTransform(_renderAlpha);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
model = glm::translate(model, blip.second.coord);
|
||||||
|
}
|
||||||
|
|
||||||
|
float a = world->getGameTime() * glm::pi<float>();
|
||||||
|
model = glm::translate(model,
|
||||||
|
glm::vec3(0.f, 0.f, 2.5f + glm::sin(a) * 0.5f));
|
||||||
|
model = glm::rotate(model, a, glm::vec3(0.f, 0.f, 1.f));
|
||||||
|
model = glm::scale(model, glm::vec3(1.5f, 1.5f, 1.5f));
|
||||||
|
objectRenderer.renderFrame(arrowModel, arrowModel->frames[0], model,
|
||||||
|
nullptr, 1.f, renderList);
|
||||||
|
}
|
||||||
|
|
||||||
RW_PROFILE_END();
|
RW_PROFILE_END();
|
||||||
|
|
||||||
renderer->pushDebugGroup("Objects");
|
renderer->pushDebugGroup("Objects");
|
||||||
@ -366,59 +374,6 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera& camera,
|
|||||||
|
|
||||||
RW_PROFILE_END();
|
RW_PROFILE_END();
|
||||||
|
|
||||||
// Render arrows above anything that isn't radar only (or hidden)
|
|
||||||
ModelRef& arrowModel = world->data->models["arrow"];
|
|
||||||
if (arrowModel && arrowModel->resource) {
|
|
||||||
auto arrowTex = world->data->textures[{"copblue", ""}];
|
|
||||||
auto arrowFrame = arrowModel->resource->findFrame("arrow");
|
|
||||||
for (auto& blip : world->state->radarBlips) {
|
|
||||||
auto dm = blip.second.display;
|
|
||||||
if (dm == BlipData::Hide || dm == BlipData::RadarOnly) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::mat4 model;
|
|
||||||
|
|
||||||
if (blip.second.target > 0) {
|
|
||||||
auto object = world->getBlipTarget(blip.second);
|
|
||||||
if (object) {
|
|
||||||
model = object->getTimeAdjustedTransform(_renderAlpha);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
model = glm::translate(model, blip.second.coord);
|
|
||||||
}
|
|
||||||
|
|
||||||
float a = world->getGameTime() * glm::pi<float>();
|
|
||||||
model = glm::translate(
|
|
||||||
model, glm::vec3(0.f, 0.f, 2.5f + glm::sin(a) * 0.5f));
|
|
||||||
model = glm::rotate(model, a, glm::vec3(0.f, 0.f, 1.f));
|
|
||||||
model = glm::scale(model, glm::vec3(1.5f, 1.5f, 1.5f));
|
|
||||||
|
|
||||||
Renderer::DrawParameters dp;
|
|
||||||
dp.textures = {arrowTex->getName()};
|
|
||||||
dp.ambient = 1.f;
|
|
||||||
dp.colour = glm::u8vec4(255, 255, 255, 255);
|
|
||||||
|
|
||||||
auto geom = arrowModel->resource
|
|
||||||
->geometries[arrowFrame->getGeometries()[0]];
|
|
||||||
Model::SubGeometry& sg = geom->subgeom[0];
|
|
||||||
|
|
||||||
dp.start = sg.start;
|
|
||||||
dp.count = sg.numIndices;
|
|
||||||
dp.diffuse = 1.f;
|
|
||||||
|
|
||||||
renderer->draw(model, &geom->dbuff, dp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw goal indicators
|
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
renderer->useProgram(particleProg);
|
|
||||||
for (auto& i : world->getAreaIndicators()) {
|
|
||||||
renderAreaIndicator(&i);
|
|
||||||
}
|
|
||||||
glDepthMask(GL_TRUE);
|
|
||||||
|
|
||||||
renderer->pushDebugGroup("Water");
|
renderer->pushDebugGroup("Water");
|
||||||
|
|
||||||
water.render(this, world);
|
water.render(this, world);
|
||||||
@ -582,33 +537,6 @@ void GameRenderer::renderGeometry(Model* model, size_t g,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GOAL_RINGS 3
|
|
||||||
void GameRenderer::renderAreaIndicator(const AreaIndicatorInfo* info) {
|
|
||||||
glm::mat4 m(1.f);
|
|
||||||
m = glm::translate(m, info->position);
|
|
||||||
glm::vec3 scale =
|
|
||||||
info->radius + 0.15f * glm::sin(_renderWorld->getGameTime() * 5.f);
|
|
||||||
|
|
||||||
Renderer::DrawParameters dp;
|
|
||||||
dp.textures = {data->findTexture("cloud1")->getName()};
|
|
||||||
dp.ambient = 1.f;
|
|
||||||
dp.colour = glm::u8vec4(50, 100, 255, 128);
|
|
||||||
dp.start = 0;
|
|
||||||
dp.count = cylinderGeometry.getCount();
|
|
||||||
dp.diffuse = 1.f;
|
|
||||||
|
|
||||||
for (int i = 0; i < GOAL_RINGS; i++) {
|
|
||||||
glm::mat4 mt = m;
|
|
||||||
glm::vec3 final = scale * glm::pow(0.9f, i + 1.0f);
|
|
||||||
mt = glm::scale(mt, glm::vec3(final.x, final.y, 1.0f + i * 0.1f));
|
|
||||||
int reverse = (i % 2 ? 1 : -1);
|
|
||||||
mt = glm::rotate(mt, reverse * _renderWorld->getGameTime() * 0.5f,
|
|
||||||
glm::vec3(0.f, 0.f, 1.f));
|
|
||||||
|
|
||||||
renderer->drawArrays(mt, &cylinderBuffer, dp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameRenderer::renderEffects(GameWorld* world) {
|
void GameRenderer::renderEffects(GameWorld* world) {
|
||||||
renderer->useProgram(particleProg);
|
renderer->useProgram(particleProg);
|
||||||
|
|
||||||
|
@ -117,9 +117,6 @@ public:
|
|||||||
DrawBuffer skyDbuff;
|
DrawBuffer skyDbuff;
|
||||||
GeometryBuffer skyGbuff;
|
GeometryBuffer skyGbuff;
|
||||||
|
|
||||||
DrawBuffer cylinderBuffer;
|
|
||||||
GeometryBuffer cylinderGeometry;
|
|
||||||
|
|
||||||
GameData* getData() const {
|
GameData* getData() const {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@ -164,9 +161,6 @@ public:
|
|||||||
void renderGeometry(Model*, size_t geom, const glm::mat4& modelMatrix,
|
void renderGeometry(Model*, size_t geom, const glm::mat4& modelMatrix,
|
||||||
float opacity, GameObject* = nullptr);
|
float opacity, GameObject* = nullptr);
|
||||||
|
|
||||||
/** Renders the area indicator */
|
|
||||||
void renderAreaIndicator(const AreaIndicatorInfo* info);
|
|
||||||
|
|
||||||
/** method for rendering AI debug information */
|
/** method for rendering AI debug information */
|
||||||
void renderPaths();
|
void renderPaths();
|
||||||
|
|
||||||
@ -196,6 +190,31 @@ public:
|
|||||||
Renderer::ProfileInfo profSky;
|
Renderer::ProfileInfo profSky;
|
||||||
Renderer::ProfileInfo profWater;
|
Renderer::ProfileInfo profWater;
|
||||||
Renderer::ProfileInfo profEffects;
|
Renderer::ProfileInfo profEffects;
|
||||||
|
|
||||||
|
enum SpecialModel {
|
||||||
|
/// @todo what is the difference between A and B
|
||||||
|
ZoneCylinderA,
|
||||||
|
ZoneCylinderB,
|
||||||
|
Arrow,
|
||||||
|
SpecialModelCount
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief setSpecialModel Set model to use for each SpecialModel
|
||||||
|
*
|
||||||
|
* GameRenderer will take ownership of the Model* pointer
|
||||||
|
*/
|
||||||
|
void setSpecialModel(SpecialModel usage, Model* model) {
|
||||||
|
specialmodels_[usage].reset(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Hard-coded models to use for each of the special models
|
||||||
|
std::unique_ptr<Model>
|
||||||
|
specialmodels_[SpecialModel::SpecialModelCount];
|
||||||
|
Model* getSpecialModel(SpecialModel usage) const {
|
||||||
|
return specialmodels_[usage].get();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -51,9 +51,9 @@ void ObjectRenderer::renderGeometry(Model* model, size_t g,
|
|||||||
dp.visibility = 1.f;
|
dp.visibility = 1.f;
|
||||||
|
|
||||||
if (object && object->type() == GameObject::Instance) {
|
if (object && object->type() == GameObject::Instance) {
|
||||||
auto instance = static_cast<InstanceObject*>(object);
|
auto modelinfo = object->getModelInfo<SimpleModelInfo>();
|
||||||
dp.depthWrite =
|
dp.depthWrite =
|
||||||
!(instance->object->flags & ObjectData::NO_ZBUFFER_WRITE);
|
!(modelinfo->flags & SimpleModelInfo::NO_ZBUFFER_WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model->geometries[g]->materials.size() > subgeom.material) {
|
if (model->geometries[g]->materials.size() > subgeom.material) {
|
||||||
@ -155,30 +155,9 @@ bool ObjectRenderer::renderFrame(Model* m, ModelFrame* f,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectRenderer::renderItem(InventoryItem* item,
|
|
||||||
const glm::mat4& modelMatrix,
|
|
||||||
RenderList& outList) {
|
|
||||||
// srhand
|
|
||||||
if (item->getModelID() == -1) {
|
|
||||||
return; // No model for this item
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<ObjectData> odata =
|
|
||||||
m_world->data->findObjectType<ObjectData>(item->getModelID());
|
|
||||||
auto weapons = m_world->data->models["weapons"];
|
|
||||||
if (weapons && weapons->resource) {
|
|
||||||
auto itemModel = weapons->resource->findFrame(odata->modelName + "_l0");
|
|
||||||
auto matrix = glm::inverse(itemModel->getTransform());
|
|
||||||
if (itemModel) {
|
|
||||||
renderFrame(weapons->resource, itemModel, modelMatrix * matrix,
|
|
||||||
nullptr, 1.f, outList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjectRenderer::renderInstance(InstanceObject* instance,
|
void ObjectRenderer::renderInstance(InstanceObject* instance,
|
||||||
RenderList& outList) {
|
RenderList& outList) {
|
||||||
if (!instance->model->resource) {
|
if (!instance->getModel()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,22 +166,24 @@ void ObjectRenderer::renderInstance(InstanceObject* instance,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto modelinfo = instance->getModelInfo<SimpleModelInfo>();
|
||||||
|
|
||||||
// Handles times provided by TOBJ data
|
// Handles times provided by TOBJ data
|
||||||
const auto currentHour = m_world->getHour();
|
const auto currentHour = m_world->getHour();
|
||||||
if (instance->object->timeOff < instance->object->timeOn) {
|
if (modelinfo->timeOff < modelinfo->timeOn) {
|
||||||
if (currentHour >= instance->object->timeOff &&
|
if (currentHour >= modelinfo->timeOff &&
|
||||||
currentHour < instance->object->timeOn)
|
currentHour < modelinfo->timeOn)
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (currentHour >= instance->object->timeOff ||
|
if (currentHour >= modelinfo->timeOff ||
|
||||||
currentHour < instance->object->timeOn)
|
currentHour < modelinfo->timeOn)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto matrixModel = instance->getTimeAdjustedTransform(m_renderAlpha);
|
auto matrixModel = instance->getTimeAdjustedTransform(m_renderAlpha);
|
||||||
|
|
||||||
float mindist = glm::length(instance->getPosition() - m_camera.position) -
|
float mindist = glm::length(instance->getPosition() - m_camera.position) -
|
||||||
instance->model->resource->getBoundingRadius();
|
instance->getModel()->getBoundingRadius();
|
||||||
mindist *= 1.f / kDrawDistanceFactor;
|
mindist *= 1.f / kDrawDistanceFactor;
|
||||||
|
|
||||||
Model* model = nullptr;
|
Model* model = nullptr;
|
||||||
@ -216,17 +197,19 @@ void ObjectRenderer::renderInstance(InstanceObject* instance,
|
|||||||
float opacity = 0.f;
|
float opacity = 0.f;
|
||||||
constexpr float fadeRange = 50.f;
|
constexpr float fadeRange = 50.f;
|
||||||
|
|
||||||
if (instance->object->numClumps == 1) {
|
/// @todo replace this block with the correct logic
|
||||||
|
if (modelinfo->getNumAtomics() == 1) {
|
||||||
// Is closest point greater than the *object* draw distance
|
// Is closest point greater than the *object* draw distance
|
||||||
float objectRange = instance->object->drawDistance[0];
|
float objectRange = modelinfo->getLodDistance(0);
|
||||||
float overlap = (mindist - objectRange);
|
float overlap = (mindist - objectRange);
|
||||||
if (mindist > objectRange) {
|
if (mindist > objectRange) {
|
||||||
// Check for LOD instances
|
// Check for LOD instances
|
||||||
if (instance->LODinstance) {
|
if (instance->LODinstance) {
|
||||||
// Is the closest point greater than the *LOD* draw distance
|
// Is the closest point greater than the *LOD* draw distance
|
||||||
float LODrange = instance->LODinstance->object->drawDistance[0];
|
auto lodmodelinfo =
|
||||||
if (mindist > LODrange) {
|
instance->LODinstance->getModelInfo<SimpleModelInfo>();
|
||||||
} else if (instance->LODinstance->model->resource) {
|
float LODrange = lodmodelinfo->getLodDistance(0);
|
||||||
|
if (mindist <= LODrange && instance->LODinstance->getModel()) {
|
||||||
// The model matrix needs to be for the LOD instead
|
// The model matrix needs to be for the LOD instead
|
||||||
matrixModel =
|
matrixModel =
|
||||||
instance->LODinstance->getTimeAdjustedTransform(
|
instance->LODinstance->getTimeAdjustedTransform(
|
||||||
@ -234,35 +217,35 @@ void ObjectRenderer::renderInstance(InstanceObject* instance,
|
|||||||
// If the object is only just out of range, keep
|
// If the object is only just out of range, keep
|
||||||
// rendering it and screen-door the LOD.
|
// rendering it and screen-door the LOD.
|
||||||
if (overlap < fadeRange) {
|
if (overlap < fadeRange) {
|
||||||
model = instance->LODinstance->model->resource;
|
model = instance->LODinstance->getModel();
|
||||||
fadingModel = instance->model->resource;
|
fadingModel = instance->getModel();
|
||||||
opacity = 1.f - (overlap / fadeRange);
|
opacity = 1.f - (overlap / fadeRange);
|
||||||
} else {
|
} else {
|
||||||
model = instance->LODinstance->model->resource;
|
model = instance->LODinstance->getModel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We don't have a LOD object, so fade out gracefully.
|
// We don't have a LOD object, so fade out gracefully.
|
||||||
else if (overlap < fadeRange) {
|
else if (overlap < fadeRange) {
|
||||||
fadingModel = instance->model->resource;
|
fadingModel = instance->getModel();
|
||||||
opacity = 1.f - (overlap / fadeRange);
|
opacity = 1.f - (overlap / fadeRange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Otherwise, if we aren't marked as a LOD model, we can render
|
// Otherwise, if we aren't marked as a LOD model, we can render
|
||||||
else if (!instance->object->LOD) {
|
else if (!modelinfo->LOD) {
|
||||||
model = instance->model->resource;
|
model = instance->getModel();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto root = instance->model->resource->frames[0];
|
auto root = instance->getModel()->frames[0];
|
||||||
auto objectModel = instance->model->resource;
|
auto objectModel = instance->getModel();
|
||||||
fadingFrame = nullptr;
|
fadingFrame = nullptr;
|
||||||
fadingModel = nullptr;
|
fadingModel = nullptr;
|
||||||
|
|
||||||
matrixModel *= root->getTransform();
|
matrixModel *= root->getTransform();
|
||||||
|
|
||||||
for (int i = 0; i < instance->object->numClumps - 1; ++i) {
|
for (int i = 0; i < modelinfo->getNumAtomics() - 1; ++i) {
|
||||||
auto ind = (instance->object->numClumps - 1) - i;
|
auto ind = (modelinfo->getNumAtomics() - 1) - i;
|
||||||
float lodDistance = instance->object->drawDistance[i];
|
float lodDistance = modelinfo->getLodDistance(i);
|
||||||
if (mindist > lodDistance) {
|
if (mindist > lodDistance) {
|
||||||
fadingFrame = root->getChildren()[ind];
|
fadingFrame = root->getChildren()[ind];
|
||||||
fadingModel = objectModel;
|
fadingModel = objectModel;
|
||||||
@ -312,15 +295,21 @@ void ObjectRenderer::renderCharacter(CharacterObject* pedestrian,
|
|||||||
matrixModel = pedestrian->getTimeAdjustedTransform(m_renderAlpha);
|
matrixModel = pedestrian->getTimeAdjustedTransform(m_renderAlpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pedestrian->model->resource) return;
|
if (!pedestrian->getModel()) return;
|
||||||
|
|
||||||
auto root = pedestrian->model->resource->frames[0];
|
auto root = pedestrian->getModel()->frames[0];
|
||||||
|
|
||||||
renderFrame(pedestrian->model->resource, root->getChildren()[0],
|
renderFrame(pedestrian->getModel(), root->getChildren()[0], matrixModel,
|
||||||
matrixModel, pedestrian, 1.f, outList);
|
pedestrian, 1.f, outList);
|
||||||
|
|
||||||
if (pedestrian->getActiveItem()) {
|
if (pedestrian->getActiveItem()) {
|
||||||
auto handFrame = pedestrian->model->resource->findFrame("srhand");
|
auto item = pedestrian->getActiveItem();
|
||||||
|
|
||||||
|
if (item->getModelID() == -1) {
|
||||||
|
return; // No model for this item
|
||||||
|
}
|
||||||
|
|
||||||
|
auto handFrame = pedestrian->getModel()->findFrame("srhand");
|
||||||
glm::mat4 localMatrix;
|
glm::mat4 localMatrix;
|
||||||
if (handFrame) {
|
if (handFrame) {
|
||||||
while (handFrame->getParent()) {
|
while (handFrame->getParent()) {
|
||||||
@ -330,91 +319,72 @@ void ObjectRenderer::renderCharacter(CharacterObject* pedestrian,
|
|||||||
handFrame = handFrame->getParent();
|
handFrame = handFrame->getParent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
renderItem(pedestrian->getActiveItem(), matrixModel * localMatrix,
|
|
||||||
outList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjectRenderer::renderWheel(VehicleObject* vehicle, Model* model,
|
// Assume items are all simple
|
||||||
const glm::mat4& matrix,
|
auto simple =
|
||||||
const std::string& name, RenderList& outList) {
|
m_world->data->findModelInfo<SimpleModelInfo>(item->getModelID());
|
||||||
for (const ModelFrame* f : model->frames) {
|
auto geometry = simple->getAtomic(0)->getGeometries().at(0);
|
||||||
const std::string& fname = f->getName();
|
renderGeometry(simple->getModel(), geometry, matrixModel * localMatrix,
|
||||||
if (fname != name) {
|
1.f, nullptr, outList);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto firstLod = f->getChildren()[0];
|
|
||||||
|
|
||||||
for (auto& g : firstLod->getGeometries()) {
|
|
||||||
RW::BSGeometryBounds& bounds = model->geometries[g]->geometryBounds;
|
|
||||||
if (!m_camera.frustum.intersects(
|
|
||||||
bounds.center + glm::vec3(matrix[3]), bounds.radius)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderGeometry(model, g, matrix, 1.f, vehicle, outList);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectRenderer::renderVehicle(VehicleObject* vehicle,
|
void ObjectRenderer::renderVehicle(VehicleObject* vehicle,
|
||||||
RenderList& outList) {
|
RenderList& outList) {
|
||||||
RW_CHECK(vehicle->model, "Vehicle model is null");
|
RW_CHECK(vehicle->getModel(), "Vehicle model is null");
|
||||||
|
|
||||||
if (!vehicle->model) {
|
if (!vehicle->getModel()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 matrixModel = vehicle->getTimeAdjustedTransform(m_renderAlpha);
|
glm::mat4 matrixModel = vehicle->getTimeAdjustedTransform(m_renderAlpha);
|
||||||
|
|
||||||
renderFrame(vehicle->model->resource, vehicle->model->resource->frames[0],
|
renderFrame(vehicle->getModel(), vehicle->getModel()->frames[0],
|
||||||
matrixModel, vehicle, 1.f, outList);
|
matrixModel, vehicle, 1.f, outList);
|
||||||
|
|
||||||
|
auto modelinfo = vehicle->getVehicle();
|
||||||
|
|
||||||
// Draw wheels n' stuff
|
// Draw wheels n' stuff
|
||||||
|
auto woi =
|
||||||
|
m_world->data->findModelInfo<SimpleModelInfo>(modelinfo->wheelmodel_);
|
||||||
|
if (!woi || !woi->isLoaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto wheelgeom = woi->getAtomic(0)->getGeometries().at(0);
|
||||||
for (size_t w = 0; w < vehicle->info->wheels.size(); ++w) {
|
for (size_t w = 0; w < vehicle->info->wheels.size(); ++w) {
|
||||||
auto woi = m_world->data->findObjectType<ObjectData>(
|
auto& wi = vehicle->physVehicle->getWheelInfo(w);
|
||||||
vehicle->vehicle->wheelModelID);
|
// Construct our own matrix so we can use the local transform
|
||||||
if (woi) {
|
vehicle->physVehicle->updateWheelTransform(w, false);
|
||||||
Model* wheelModel = m_world->data->models["wheels"]->resource;
|
/// @todo migrate this into Vehicle physics tick so we can
|
||||||
auto& wi = vehicle->physVehicle->getWheelInfo(w);
|
/// interpolate old -> new
|
||||||
if (wheelModel) {
|
|
||||||
// Construct our own matrix so we can use the local transform
|
|
||||||
vehicle->physVehicle->updateWheelTransform(w, false);
|
|
||||||
/// @todo migrate this into Vehicle physics tick so we can
|
|
||||||
/// interpolate old -> new
|
|
||||||
|
|
||||||
glm::mat4 wheelM(matrixModel);
|
glm::mat4 wheelM(matrixModel);
|
||||||
|
|
||||||
auto up = -wi.m_wheelDirectionCS;
|
auto up = -wi.m_wheelDirectionCS;
|
||||||
auto right = wi.m_wheelAxleCS;
|
auto right = wi.m_wheelAxleCS;
|
||||||
auto fwd = up.cross(right);
|
auto fwd = up.cross(right);
|
||||||
btQuaternion steerQ(up, wi.m_steering);
|
btQuaternion steerQ(up, wi.m_steering);
|
||||||
btQuaternion rollQ(right, -wi.m_rotation);
|
btQuaternion rollQ(right, -wi.m_rotation);
|
||||||
|
|
||||||
btMatrix3x3 basis(right[0], fwd[0], up[0], right[1], fwd[1],
|
btMatrix3x3 basis(right[0], fwd[0], up[0], right[1], fwd[1], up[1],
|
||||||
up[1], right[2], fwd[2], up[2]);
|
right[2], fwd[2], up[2]);
|
||||||
|
|
||||||
btTransform t;
|
btTransform t;
|
||||||
t.setBasis(btMatrix3x3(steerQ) * btMatrix3x3(rollQ) * basis);
|
t.setBasis(btMatrix3x3(steerQ) * btMatrix3x3(rollQ) * basis);
|
||||||
t.setOrigin(wi.m_chassisConnectionPointCS +
|
t.setOrigin(wi.m_chassisConnectionPointCS +
|
||||||
wi.m_wheelDirectionCS *
|
wi.m_wheelDirectionCS *
|
||||||
wi.m_raycastInfo.m_suspensionLength);
|
wi.m_raycastInfo.m_suspensionLength);
|
||||||
|
|
||||||
t.getOpenGLMatrix(glm::value_ptr(wheelM));
|
t.getOpenGLMatrix(glm::value_ptr(wheelM));
|
||||||
wheelM = matrixModel * wheelM;
|
wheelM = matrixModel * wheelM;
|
||||||
|
|
||||||
wheelM =
|
wheelM = glm::scale(wheelM, glm::vec3(modelinfo->wheelscale_));
|
||||||
glm::scale(wheelM, glm::vec3(vehicle->vehicle->wheelScale));
|
if (wi.m_chassisConnectionPointCS.x() < 0.f) {
|
||||||
if (wi.m_chassisConnectionPointCS.x() < 0.f) {
|
wheelM = glm::scale(wheelM, glm::vec3(-1.f, 1.f, 1.f));
|
||||||
wheelM = glm::scale(wheelM, glm::vec3(-1.f, 1.f, 1.f));
|
|
||||||
}
|
|
||||||
|
|
||||||
renderWheel(vehicle, wheelModel, wheelM, woi->modelName,
|
|
||||||
outList);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderGeometry(woi->getModel(), wheelgeom, wheelM, 1.f, nullptr,
|
||||||
|
outList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,44 +395,25 @@ void ObjectRenderer::renderPickup(PickupObject* pickup, RenderList& outList) {
|
|||||||
modelMatrix = glm::rotate(modelMatrix, m_world->getGameTime(),
|
modelMatrix = glm::rotate(modelMatrix, m_world->getGameTime(),
|
||||||
glm::vec3(0.f, 0.f, 1.f));
|
glm::vec3(0.f, 0.f, 1.f));
|
||||||
|
|
||||||
auto odata =
|
auto odata = pickup->getModelInfo<SimpleModelInfo>();
|
||||||
m_world->data->findObjectType<ObjectData>(pickup->getModelID());
|
|
||||||
|
|
||||||
Model* model = nullptr;
|
auto model = odata->getModel();
|
||||||
ModelFrame* itemModel = nullptr;
|
auto itemModel = odata->getAtomic(0);
|
||||||
|
auto geom = 0;
|
||||||
/// @todo Better determination of is this object a weapon.
|
if (!itemModel->getGeometries().empty()) {
|
||||||
if (odata->ID >= 170 && odata->ID <= 184) {
|
geom = itemModel->getGeometries()[0];
|
||||||
auto weapons = m_world->data->models["weapons"];
|
} else if (!itemModel->getChildren().empty()) {
|
||||||
if (weapons && weapons->resource && odata) {
|
geom = itemModel->getChildren()[0]->getGeometries()[0];
|
||||||
model = weapons->resource;
|
|
||||||
itemModel = weapons->resource->findFrame(odata->modelName + "_l0");
|
|
||||||
RW_CHECK(itemModel, "Weapon Frame not present int weapon model");
|
|
||||||
if (!itemModel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
auto handle = m_world->data->models[odata->modelName];
|
|
||||||
RW_CHECK(handle && handle->resource, "Pickup has no model");
|
|
||||||
if (handle && handle->resource) {
|
|
||||||
model = handle->resource;
|
|
||||||
itemModel = model->frames[model->rootFrameIdx];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemModel) {
|
renderGeometry(model, geom, modelMatrix, 1.f, pickup, outList);
|
||||||
auto matrix = glm::inverse(itemModel->getTransform());
|
|
||||||
renderFrame(model, itemModel, modelMatrix * matrix, pickup, 1.f,
|
|
||||||
outList);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectRenderer::renderCutsceneObject(CutsceneObject* cutscene,
|
void ObjectRenderer::renderCutsceneObject(CutsceneObject* cutscene,
|
||||||
RenderList& outList) {
|
RenderList& outList) {
|
||||||
if (!m_world->state->currentCutscene) return;
|
if (!m_world->state->currentCutscene) return;
|
||||||
|
|
||||||
if (!cutscene->model->resource) {
|
if (!cutscene->getModel()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,7 +439,7 @@ void ObjectRenderer::renderCutsceneObject(CutsceneObject* cutscene,
|
|||||||
matrixModel = glm::translate(matrixModel, cutsceneOffset);
|
matrixModel = glm::translate(matrixModel, cutsceneOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto model = cutscene->model->resource;
|
auto model = cutscene->getModel();
|
||||||
if (cutscene->getParentActor()) {
|
if (cutscene->getParentActor()) {
|
||||||
glm::mat4 align;
|
glm::mat4 align;
|
||||||
/// @todo figure out where this 90 degree offset is coming from.
|
/// @todo figure out where this 90 degree offset is coming from.
|
||||||
@ -505,21 +456,14 @@ void ObjectRenderer::renderProjectile(ProjectileObject* projectile,
|
|||||||
RenderList& outList) {
|
RenderList& outList) {
|
||||||
glm::mat4 modelMatrix = projectile->getTimeAdjustedTransform(m_renderAlpha);
|
glm::mat4 modelMatrix = projectile->getTimeAdjustedTransform(m_renderAlpha);
|
||||||
|
|
||||||
auto odata = m_world->data->findObjectType<ObjectData>(
|
auto odata = m_world->data->findModelInfo<SimpleModelInfo>(
|
||||||
projectile->getProjectileInfo().weapon->modelID);
|
projectile->getProjectileInfo().weapon->modelID);
|
||||||
auto weapons = m_world->data->models["weapons"];
|
|
||||||
|
|
||||||
RW_CHECK(weapons, "Weapons model not loaded");
|
auto model = odata->getModel();
|
||||||
|
auto modelframe = odata->getAtomic(0);
|
||||||
|
auto geom = modelframe->getGeometries().at(0);
|
||||||
|
|
||||||
if (weapons && weapons->resource) {
|
renderGeometry(model, geom, modelMatrix, 1.f, projectile, outList);
|
||||||
auto itemModel = weapons->resource->findFrame(odata->modelName + "_l0");
|
|
||||||
auto matrix = glm::inverse(itemModel->getTransform());
|
|
||||||
RW_CHECK(itemModel, "Weapon frame not in model");
|
|
||||||
if (itemModel) {
|
|
||||||
renderFrame(weapons->resource, itemModel, modelMatrix * matrix,
|
|
||||||
projectile, 1.f, outList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectRenderer::buildRenderList(GameObject* object, RenderList& outList) {
|
void ObjectRenderer::buildRenderList(GameObject* object, RenderList& outList) {
|
||||||
|
@ -35,6 +35,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
void buildRenderList(GameObject* object, RenderList& outList);
|
void buildRenderList(GameObject* object, RenderList& outList);
|
||||||
|
|
||||||
|
bool renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix,
|
||||||
|
GameObject* object, float opacity, RenderList& outList);
|
||||||
|
|
||||||
|
void renderGeometry(Model* model, size_t g, const glm::mat4& modelMatrix,
|
||||||
|
float opacity, GameObject* object, RenderList& outList);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GameWorld* m_world;
|
GameWorld* m_world;
|
||||||
const ViewCamera& m_camera;
|
const ViewCamera& m_camera;
|
||||||
@ -47,18 +53,6 @@ private:
|
|||||||
void renderPickup(PickupObject* pickup, RenderList& outList);
|
void renderPickup(PickupObject* pickup, RenderList& outList);
|
||||||
void renderCutsceneObject(CutsceneObject* cutscene, RenderList& outList);
|
void renderCutsceneObject(CutsceneObject* cutscene, RenderList& outList);
|
||||||
void renderProjectile(ProjectileObject* projectile, RenderList& outList);
|
void renderProjectile(ProjectileObject* projectile, RenderList& outList);
|
||||||
|
|
||||||
void renderItem(InventoryItem* item, const glm::mat4& modelMatrix,
|
|
||||||
RenderList& outList);
|
|
||||||
void renderWheel(VehicleObject* vehicle, Model* model,
|
|
||||||
const glm::mat4& matrix, const std::string& name,
|
|
||||||
RenderList& outList);
|
|
||||||
|
|
||||||
bool renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix,
|
|
||||||
GameObject* object, float opacity, RenderList& outList);
|
|
||||||
|
|
||||||
void renderGeometry(Model* model, size_t g, const glm::mat4& modelMatrix,
|
|
||||||
float opacity, GameObject* object, RenderList& outList);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,12 +31,11 @@ inline VehicleObject* getCharacterVehicle(CharacterObject* character) {
|
|||||||
}
|
}
|
||||||
inline bool isInModel(const ScriptArguments& args, CharacterObject* character,
|
inline bool isInModel(const ScriptArguments& args, CharacterObject* character,
|
||||||
int model) {
|
int model) {
|
||||||
auto data = args.getWorld()->data->findObjectType<VehicleData>(model);
|
auto data = args.getWorld()->data->findModelInfo<VehicleModelInfo>(model);
|
||||||
if (data) {
|
if (data) {
|
||||||
auto vehicle = getCharacterVehicle(character);
|
auto vehicle = getCharacterVehicle(character);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
return vehicle->model ? vehicle->model->name == data->modelName
|
return vehicle->getVehicle()->id() == model;
|
||||||
: false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -3546,12 +3546,8 @@ void opcode_0136(const ScriptArguments& args, const ScriptInt arg1, const Script
|
|||||||
@arg model Model ID
|
@arg model Model ID
|
||||||
*/
|
*/
|
||||||
bool opcode_0137(const ScriptArguments& args, const ScriptVehicle vehicle, const ScriptModelID model) {
|
bool opcode_0137(const ScriptArguments& args, const ScriptVehicle vehicle, const ScriptModelID model) {
|
||||||
auto data = args.getWorld()->data->findObjectType<VehicleData>(model);
|
RW_UNUSED(args);
|
||||||
RW_CHECK(data, "non-vehicle model ID");
|
return vehicle->getVehicle()->id() == model;
|
||||||
if (data) {
|
|
||||||
return vehicle->model->name == data->modelName;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -6840,12 +6836,18 @@ void opcode_023c(const ScriptArguments& args, const ScriptInt arg1, const Script
|
|||||||
@arg arg1
|
@arg arg1
|
||||||
*/
|
*/
|
||||||
bool opcode_023d(const ScriptArguments& args, const ScriptInt arg1) {
|
bool opcode_023d(const ScriptArguments& args, const ScriptInt arg1) {
|
||||||
|
/// @todo re-implement this when streaming is added
|
||||||
|
return true;
|
||||||
|
RW_UNUSED(args);
|
||||||
|
RW_UNUSED(arg1);
|
||||||
|
#if 0
|
||||||
auto model = args.getState()->specialCharacters[arg1];
|
auto model = args.getState()->specialCharacters[arg1];
|
||||||
auto modelfind = args.getWorld()->data->models.find(model);
|
auto modelfind = args.getWorld()->data->models.find(model);
|
||||||
if( modelfind != args.getWorld()->data->models.end() && modelfind->second->resource != nullptr ) {
|
if( modelfind != args.getWorld()->data->models.end() && modelfind->second->resource != nullptr ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8156,7 +8158,11 @@ void opcode_02dd(const ScriptArguments& args, const ScriptString areaName, Scrip
|
|||||||
bool opcode_02de(const ScriptArguments& args, const ScriptPlayer player) {
|
bool opcode_02de(const ScriptArguments& args, const ScriptPlayer player) {
|
||||||
RW_UNUSED(args);
|
RW_UNUSED(args);
|
||||||
auto vehicle = player->getCharacter()->getCurrentVehicle();
|
auto vehicle = player->getCharacter()->getCurrentVehicle();
|
||||||
return (vehicle && (vehicle->vehicle->classType & VehicleData::TAXI) == VehicleData::TAXI);
|
if (!vehicle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto type = vehicle->getVehicle()->vehicleclass_;
|
||||||
|
return (type & VehicleModelInfo::TAXI) == VehicleModelInfo::TAXI;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8455,7 +8461,7 @@ void opcode_02f4(const ScriptArguments& args, const ScriptObject object0, const
|
|||||||
auto actor = args.getObject<CutsceneObject>(0);
|
auto actor = args.getObject<CutsceneObject>(0);
|
||||||
CutsceneObject* object = args.getWorld()->createCutsceneObject(id, args.getWorld()->state->currentCutscene->meta.sceneOffset );
|
CutsceneObject* object = args.getWorld()->createCutsceneObject(id, args.getWorld()->state->currentCutscene->meta.sceneOffset );
|
||||||
|
|
||||||
auto headframe = actor->model->resource->findFrame("shead");
|
auto headframe = actor->getModel()->findFrame("shead");
|
||||||
actor->skeleton->setEnabled(headframe, false);
|
actor->skeleton->setEnabled(headframe, false);
|
||||||
object->setParentActor(actor, headframe);
|
object->setParentActor(actor, headframe);
|
||||||
|
|
||||||
@ -10063,7 +10069,8 @@ void opcode_0363(const ScriptArguments& args, ScriptVec3 coord, const ScriptFloa
|
|||||||
InstanceObject* object = static_cast<InstanceObject*>(i.second);
|
InstanceObject* object = static_cast<InstanceObject*>(i.second);
|
||||||
|
|
||||||
// Check if this instance has the correct model id, early out if it isn't
|
// Check if this instance has the correct model id, early out if it isn't
|
||||||
if (!boost::iequals(object->object->modelName, modelName)) {
|
auto modelinfo = object->getModelInfo<BaseModelInfo>();
|
||||||
|
if (!boost::iequals(modelinfo->name, modelName)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11343,19 +11350,16 @@ void opcode_03b6(const ScriptArguments& args, ScriptVec3 coord, const ScriptFloa
|
|||||||
std::transform(oldmodel.begin(), oldmodel.end(), oldmodel.begin(), ::tolower);
|
std::transform(oldmodel.begin(), oldmodel.end(), oldmodel.begin(), ::tolower);
|
||||||
|
|
||||||
auto newobjectid = args.getWorld()->data->findModelObject(newmodel);
|
auto newobjectid = args.getWorld()->data->findModelObject(newmodel);
|
||||||
auto nobj = args.getWorld()->data->findObjectType<ObjectData>(newobjectid);
|
auto nobj = args.getWorld()->data->findModelInfo<SimpleModelInfo>(newobjectid);
|
||||||
|
|
||||||
/// @todo Objects need to adopt the new object ID, not just the model.
|
|
||||||
for(auto p : args.getWorld()->instancePool.objects) {
|
for(auto p : args.getWorld()->instancePool.objects) {
|
||||||
auto o = p.second;
|
auto o = p.second;
|
||||||
if( !o->model ) continue;
|
if( !o->getModel() ) continue;
|
||||||
if( o->model->name != oldmodel ) continue;
|
if( o->getModelInfo<BaseModelInfo>()->name != oldmodel ) continue;
|
||||||
float d = glm::distance(coord, o->getPosition());
|
float d = glm::distance(coord, o->getPosition());
|
||||||
if( d < radius ) {
|
if( d < radius ) {
|
||||||
args.getWorld()->data->loadDFF(newmodel + ".dff", false);
|
|
||||||
InstanceObject* inst = static_cast<InstanceObject*>(o);
|
InstanceObject* inst = static_cast<InstanceObject*>(o);
|
||||||
inst->changeModel(nobj);
|
inst->changeModel(nobj);
|
||||||
inst->model = args.getWorld()->data->models[newmodel];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,10 +157,10 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
|
|||||||
if (current) {
|
if (current) {
|
||||||
uint16_t model = current->getModelID();
|
uint16_t model = current->getModelID();
|
||||||
if (model > 0) {
|
if (model > 0) {
|
||||||
ObjectDataPtr weaponData =
|
auto weaponData =
|
||||||
world->data->findObjectType<ObjectData>(model);
|
world->data->findModelInfo<SimpleModelInfo>(model);
|
||||||
if (weaponData != nullptr) {
|
if (weaponData != nullptr) {
|
||||||
itemTextureName = weaponData->modelName;
|
itemTextureName = weaponData->name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,11 @@
|
|||||||
const std::string kBuildStr(kGitSHA1Hash, 8);
|
const std::string kBuildStr(kGitSHA1Hash, 8);
|
||||||
const std::string kWindowTitle = "RWGame";
|
const std::string kWindowTitle = "RWGame";
|
||||||
|
|
||||||
|
std::map<GameRenderer::SpecialModel, std::string> kSpecialModels = {
|
||||||
|
{GameRenderer::ZoneCylinderA, "zonecyla.dff"},
|
||||||
|
{GameRenderer::ZoneCylinderB, "zonecylb.dff"},
|
||||||
|
{GameRenderer::Arrow, "arrow.dff"}};
|
||||||
|
|
||||||
#define MOUSE_SENSITIVITY_SCALE 2.5f
|
#define MOUSE_SENSITIVITY_SCALE 2.5f
|
||||||
|
|
||||||
DebugDraw* debug = nullptr;
|
DebugDraw* debug = nullptr;
|
||||||
@ -124,6 +129,11 @@ RWGame::RWGame(int argc, char* argv[]) {
|
|||||||
// Initialize renderer
|
// Initialize renderer
|
||||||
renderer = new GameRenderer(&log, data);
|
renderer = new GameRenderer(&log, data);
|
||||||
|
|
||||||
|
for (const auto& p : kSpecialModels) {
|
||||||
|
auto model = data->loadClump(p.second);
|
||||||
|
renderer->setSpecialModel(p.first, model);
|
||||||
|
}
|
||||||
|
|
||||||
// Set up text renderer
|
// Set up text renderer
|
||||||
renderer->text.setFontTexture(0, "pager");
|
renderer->text.setFontTexture(0, "pager");
|
||||||
renderer->text.setFontTexture(1, "font1");
|
renderer->text.setFontTexture(1, "font1");
|
||||||
|
@ -201,7 +201,8 @@ Menu* DebugState::createMapMenu() {
|
|||||||
for (auto& i : gw->instancePool.objects) {
|
for (auto& i : gw->instancePool.objects) {
|
||||||
auto obj = static_cast<InstanceObject*>(i.second);
|
auto obj = static_cast<InstanceObject*>(i.second);
|
||||||
if (std::find(garageDoorModels.begin(), garageDoorModels.end(),
|
if (std::find(garageDoorModels.begin(), garageDoorModels.end(),
|
||||||
obj->model->name) != garageDoorModels.end()) {
|
obj->getModelInfo<BaseModelInfo>()->name) !=
|
||||||
|
garageDoorModels.end()) {
|
||||||
obj->setSolid(false);
|
obj->setSolid(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,26 +114,11 @@ void IngameState::startTest() {
|
|||||||
|
|
||||||
auto carPos = glm::vec3(286.f, -591.f, 37.f);
|
auto carPos = glm::vec3(286.f, -591.f, 37.f);
|
||||||
auto carRot = glm::angleAxis(glm::radians(90.f), glm::vec3(0.f, 0.f, 1.f));
|
auto carRot = glm::angleAxis(glm::radians(90.f), glm::vec3(0.f, 0.f, 1.f));
|
||||||
// auto boatPos = glm::vec3( -1000.f, -1040.f, 5.f );
|
// Landstalker, Stinger, Linerunner, Trash, Bobcat
|
||||||
int i = 0;
|
const std::vector<int> kTestVehicles = {90, 92, 93, 98, 111};
|
||||||
for (auto& vi : getWorld()->data->objectTypes) {
|
for (auto id : kTestVehicles) {
|
||||||
switch (vi.first) {
|
getWorld()->createVehicle(id, carPos, carRot);
|
||||||
case 140:
|
carPos += carRot * glm::vec3(5.f, 0.f, 0.f);
|
||||||
continue;
|
|
||||||
case 141:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (vi.second->class_type == ObjectInformation::_class("CARS")) {
|
|
||||||
if (i++ > 20) break;
|
|
||||||
auto vehicle = std::static_pointer_cast<VehicleData>(vi.second);
|
|
||||||
|
|
||||||
auto& sp = carPos;
|
|
||||||
auto& sr = carRot;
|
|
||||||
auto v = getWorld()->createVehicle(vi.first, sp, sr);
|
|
||||||
|
|
||||||
sp +=
|
|
||||||
sr * glm::vec3(2.f + v->info->handling.dimensions.x, 0.f, 0.f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,9 +224,9 @@ void IngameState::tick(float dt) {
|
|||||||
? static_cast<CharacterObject*>(target)->getCurrentVehicle()
|
? static_cast<CharacterObject*>(target)->getCurrentVehicle()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
auto model = vehicle->model;
|
auto model = vehicle->getModel();
|
||||||
float maxDist = 0.f;
|
float maxDist = 0.f;
|
||||||
for (auto& g : model->resource->geometries) {
|
for (auto& g : model->geometries) {
|
||||||
float partSize = glm::length(g->geometryBounds.center) +
|
float partSize = glm::length(g->geometryBounds.center) +
|
||||||
g->geometryBounds.radius;
|
g->geometryBounds.radius;
|
||||||
maxDist = std::max(partSize, maxDist);
|
maxDist = std::max(partSize, maxDist);
|
||||||
|
@ -23,7 +23,6 @@ SET(RWLIB_SOURCES
|
|||||||
"source/platform/FileIndex.hpp"
|
"source/platform/FileIndex.hpp"
|
||||||
"source/platform/FileIndex.cpp"
|
"source/platform/FileIndex.cpp"
|
||||||
|
|
||||||
"source/data/ResourceHandle.hpp"
|
|
||||||
"source/data/Model.hpp"
|
"source/data/Model.hpp"
|
||||||
"source/data/Model.cpp"
|
"source/data/Model.cpp"
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <data/ResourceHandle.hpp>
|
|
||||||
#include <gl/DrawBuffer.hpp>
|
#include <gl/DrawBuffer.hpp>
|
||||||
#include <gl/GeometryBuffer.hpp>
|
#include <gl/GeometryBuffer.hpp>
|
||||||
#include <gl/TextureData.hpp>
|
#include <gl/TextureData.hpp>
|
||||||
@ -180,6 +179,4 @@ private:
|
|||||||
float boundingRadius;
|
float boundingRadius;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ResourceHandle<Model>::Ref ModelRef;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace RW {
|
|
||||||
/**
|
|
||||||
* Possible states for ResourceHandle
|
|
||||||
*/
|
|
||||||
enum ResourceState {
|
|
||||||
/// Resource has been declared but not loaded
|
|
||||||
Loading = 0,
|
|
||||||
/// Resource has been loaded and is available
|
|
||||||
Loaded = 1,
|
|
||||||
/// Loading the resource failed
|
|
||||||
Failed = 2
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class ResourceHandle {
|
|
||||||
public:
|
|
||||||
T* resource;
|
|
||||||
RW::ResourceState state;
|
|
||||||
std::string name;
|
|
||||||
|
|
||||||
typedef std::shared_ptr<ResourceHandle<T>> Ref;
|
|
||||||
|
|
||||||
ResourceHandle(const std::string& name)
|
|
||||||
: resource(nullptr), state(RW::Loading), name(name) {
|
|
||||||
}
|
|
||||||
};
|
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#include <loaders/RWBinaryStream.hpp>
|
#include <loaders/RWBinaryStream.hpp>
|
||||||
|
|
||||||
#include <data/ResourceHandle.hpp>
|
|
||||||
#include <platform/FileHandle.hpp>
|
#include <platform/FileHandle.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#include <engine/GameData.hpp>
|
#include <engine/GameData.hpp>
|
||||||
|
|
||||||
qint16 ItemListModel::getIDOf(unsigned int row) const {
|
qint16 ItemListModel::getIDOf(unsigned int row) const {
|
||||||
if (row < world()->data->objectTypes.size()) {
|
if (row < world()->data->modelinfo.size()) {
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ ItemListModel::ItemListModel(GameWorld *world, QObject *parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ItemListModel::rowCount(const QModelIndex &parent) const {
|
int ItemListModel::rowCount(const QModelIndex &parent) const {
|
||||||
return _world->data->objectTypes.size();
|
return _world->data->modelinfo.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ItemListModel::columnCount(const QModelIndex &parent) const {
|
int ItemListModel::columnCount(const QModelIndex &parent) const {
|
||||||
|
@ -177,19 +177,24 @@ void ViewerWidget::showObject(qint16 item) {
|
|||||||
|
|
||||||
if (dummyObject) gworld->destroyObject(dummyObject);
|
if (dummyObject) gworld->destroyObject(dummyObject);
|
||||||
|
|
||||||
auto def = world()->data->objectTypes[item];
|
auto def = world()->data->modelinfo[item].get();
|
||||||
|
|
||||||
if (def) {
|
if (def) {
|
||||||
if (def->class_type == ObjectData::class_id) {
|
switch (def->type()) {
|
||||||
dummyObject = gworld->createInstance(item, {});
|
default:
|
||||||
} else if (def->class_type == CharacterData::class_id) {
|
dummyObject = gworld->createInstance(item, {});
|
||||||
dummyObject = gworld->createPedestrian(item, {});
|
break;
|
||||||
} else if (def->class_type == VehicleData::class_id) {
|
case ModelDataType::PedInfo:
|
||||||
dummyObject = gworld->createVehicle(item, {});
|
dummyObject = gworld->createPedestrian(item, {});
|
||||||
|
break;
|
||||||
|
case ModelDataType::VehicleInfo:
|
||||||
|
dummyObject = gworld->createVehicle(item, {});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
RW_CHECK(dummyObject != nullptr, "Dummy Object is null");
|
RW_CHECK(dummyObject != nullptr, "Dummy Object is null");
|
||||||
if (dummyObject != nullptr) {
|
if (dummyObject != nullptr) {
|
||||||
activeModel = dummyObject->model->resource;
|
activeModel = dummyObject->getModel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,19 +5,13 @@ ObjectListModel::ObjectListModel(GameData *dat, QObject *parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ObjectListModel::rowCount(const QModelIndex &parent) const {
|
int ObjectListModel::rowCount(const QModelIndex &parent) const {
|
||||||
return _gameData->objectTypes.size();
|
return _gameData->modelinfo.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ObjectListModel::columnCount(const QModelIndex &parent) const {
|
int ObjectListModel::columnCount(const QModelIndex &parent) const {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::map<ObjectInformation::ObjectClass, QString> gDataType = {
|
|
||||||
{ObjectInformation::_class("OBJS"), "Object"},
|
|
||||||
{ObjectInformation::_class("CARS"), "Vehicle"},
|
|
||||||
{ObjectInformation::_class("PEDS"), "Pedestrian"},
|
|
||||||
{ObjectInformation::_class("HIER"), "Cutscene"}};
|
|
||||||
|
|
||||||
QVariant ObjectListModel::data(const QModelIndex &index, int role) const {
|
QVariant ObjectListModel::data(const QModelIndex &index, int role) const {
|
||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole) {
|
||||||
auto id = index.internalId();
|
auto id = index.internalId();
|
||||||
@ -25,23 +19,12 @@ QVariant ObjectListModel::data(const QModelIndex &index, int role) const {
|
|||||||
if (index.column() == 0) {
|
if (index.column() == 0) {
|
||||||
return id;
|
return id;
|
||||||
} else if (index.column() == 1) {
|
} else if (index.column() == 1) {
|
||||||
auto object = _gameData->objectTypes[id];
|
auto object = _gameData->modelinfo[id].get();
|
||||||
if (gDataType[object->class_type].isEmpty()) {
|
return QString::fromStdString(
|
||||||
return QString("Unknown");
|
BaseModelInfo::getTypeName(object->type()));
|
||||||
}
|
|
||||||
return gDataType[object->class_type];
|
|
||||||
} else if (index.column() == 2) {
|
} else if (index.column() == 2) {
|
||||||
auto object = _gameData->objectTypes[id];
|
auto object = _gameData->modelinfo[id].get();
|
||||||
if (object->class_type == ObjectData::class_id) {
|
return QString::fromStdString(object->name);
|
||||||
auto v = std::static_pointer_cast<ObjectData>(object);
|
|
||||||
return QString::fromStdString(v->modelName);
|
|
||||||
} else if (object->class_type == VehicleData::class_id) {
|
|
||||||
auto v = std::static_pointer_cast<VehicleData>(object);
|
|
||||||
return QString::fromStdString(v->modelName);
|
|
||||||
} else if (object->class_type == CharacterData::class_id) {
|
|
||||||
auto v = std::static_pointer_cast<CharacterData>(object);
|
|
||||||
return QString::fromStdString(v->modelName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QVariant::Invalid;
|
return QVariant::Invalid;
|
||||||
@ -64,9 +47,9 @@ QVariant ObjectListModel::headerData(int section, Qt::Orientation orientation,
|
|||||||
|
|
||||||
QModelIndex ObjectListModel::index(int row, int column,
|
QModelIndex ObjectListModel::index(int row, int column,
|
||||||
const QModelIndex &parent) const {
|
const QModelIndex &parent) const {
|
||||||
auto it = _gameData->objectTypes.begin();
|
auto it = _gameData->modelinfo.begin();
|
||||||
for (int i = 0; i < row; i++) it++;
|
for (int i = 0; i < row; i++) it++;
|
||||||
auto id = it->second->ID;
|
auto id = it->second->id();
|
||||||
|
|
||||||
return hasIndex(row, column, parent) ? createIndex(row, column, id)
|
return hasIndex(row, column, parent) ? createIndex(row, column, id)
|
||||||
: QModelIndex();
|
: QModelIndex();
|
||||||
|
@ -60,30 +60,14 @@ void ObjectViewer::worldChanged() {
|
|||||||
SLOT(showItem(QModelIndex)));
|
SLOT(showItem(QModelIndex)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::map<ObjectInformation::ObjectClass, QString> gDataType = {
|
|
||||||
{ObjectInformation::_class("OBJS"), "Object"},
|
|
||||||
{ObjectInformation::_class("CARS"), "Vehicle"},
|
|
||||||
{ObjectInformation::_class("PEDS"), "Pedestrian"},
|
|
||||||
{ObjectInformation::_class("HIER"), "Cutscene"}};
|
|
||||||
|
|
||||||
void ObjectViewer::showItem(qint16 item) {
|
void ObjectViewer::showItem(qint16 item) {
|
||||||
auto def = world()->data->objectTypes[item];
|
auto def = world()->data->modelinfo[item].get();
|
||||||
|
|
||||||
if (def) {
|
if (def) {
|
||||||
previewID->setText(QString::number(def->ID));
|
previewID->setText(QString::number(def->id()));
|
||||||
previewClass->setText(gDataType[def->class_type]);
|
previewClass->setText(
|
||||||
|
QString::fromStdString(BaseModelInfo::getTypeName(def->type())));
|
||||||
if (def->class_type == ObjectData::class_id) {
|
previewModel->setText(QString::fromStdString(def->name));
|
||||||
auto v = std::static_pointer_cast<ObjectData>(def);
|
|
||||||
previewModel->setText(QString::fromStdString(v->modelName));
|
|
||||||
} else if (def->class_type == VehicleData::class_id) {
|
|
||||||
auto v = std::static_pointer_cast<VehicleData>(def);
|
|
||||||
previewModel->setText(QString::fromStdString(v->modelName));
|
|
||||||
} else if (def->class_type == CharacterData::class_id) {
|
|
||||||
auto v = std::static_pointer_cast<CharacterData>(def);
|
|
||||||
previewModel->setText(QString::fromStdString(v->modelName));
|
|
||||||
}
|
|
||||||
|
|
||||||
previewWidget->showObject(item);
|
previewWidget->showObject(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@ set(TEST_SOURCES
|
|||||||
"test_object_data.cpp"
|
"test_object_data.cpp"
|
||||||
"test_pickup.cpp"
|
"test_pickup.cpp"
|
||||||
"test_renderer.cpp"
|
"test_renderer.cpp"
|
||||||
"test_Resource.cpp"
|
|
||||||
"test_rwbstream.cpp"
|
"test_rwbstream.cpp"
|
||||||
"test_SaveGame.cpp"
|
"test_SaveGame.cpp"
|
||||||
"test_scriptmachine.cpp"
|
"test_scriptmachine.cpp"
|
||||||
|
@ -12,16 +12,16 @@ BOOST_AUTO_TEST_CASE(test_object_data) {
|
|||||||
gd.load();
|
gd.load();
|
||||||
|
|
||||||
{
|
{
|
||||||
auto def = gd.findObjectType<ObjectData>(1100);
|
auto def = gd.findModelInfo<SimpleModelInfo>(1100);
|
||||||
|
|
||||||
BOOST_REQUIRE(def);
|
BOOST_REQUIRE(def);
|
||||||
|
|
||||||
BOOST_ASSERT(def->class_type == ObjectInformation::_class("OBJS"));
|
BOOST_ASSERT(def->type() == ModelDataType::SimpleInfo);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(def->modelName, "rd_Corner1");
|
BOOST_CHECK_EQUAL(def->name, "rd_Corner1");
|
||||||
BOOST_CHECK_EQUAL(def->textureName, "generic");
|
BOOST_CHECK_EQUAL(def->textureslot, "generic");
|
||||||
BOOST_CHECK_EQUAL(def->numClumps, 1);
|
BOOST_CHECK_EQUAL(def->getNumAtomics(), 1);
|
||||||
BOOST_CHECK_EQUAL(def->drawDistance[0], 220);
|
BOOST_CHECK_EQUAL(def->getLodDistance(0), 220);
|
||||||
BOOST_CHECK_EQUAL(def->flags, 0);
|
BOOST_CHECK_EQUAL(def->flags, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
#include <boost/test/unit_test.hpp>
|
|
||||||
#include <data/ResourceHandle.hpp>
|
|
||||||
#include <test_globals.hpp>
|
|
||||||
|
|
||||||
typedef ResourceHandle<int>::Ref IntRef;
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(ResourceTests)
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_ResourceHandle) {
|
|
||||||
int resource = 42;
|
|
||||||
IntRef ref{new ResourceHandle<int>("")};
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(ref->resource, nullptr);
|
|
||||||
BOOST_CHECK_EQUAL(ref->state, RW::Loading);
|
|
||||||
|
|
||||||
ref->state = RW::Loaded;
|
|
||||||
ref->resource = &resource;
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(ref->resource, &resource);
|
|
||||||
BOOST_CHECK_EQUAL(ref->state, RW::Loaded);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
|
@ -15,10 +15,9 @@ BOOST_AUTO_TEST_CASE(test_matrix) {
|
|||||||
|
|
||||||
/** Models are currently needed to relate animation bones <=> model
|
/** Models are currently needed to relate animation bones <=> model
|
||||||
* frame #s. */
|
* frame #s. */
|
||||||
Global::get().e->data->loadDFF("player.dff");
|
auto test_model = Global::get().d->loadClump("player.dff");
|
||||||
ModelRef& test_model = Global::get().e->data->models["player"];
|
|
||||||
|
|
||||||
Animator animator(test_model->resource, &skeleton);
|
Animator animator(test_model, &skeleton);
|
||||||
|
|
||||||
animation.duration = 1.f;
|
animation.duration = 1.f;
|
||||||
animation.bones["player"] = new AnimationBone{
|
animation.bones["player"] = new AnimationBone{
|
||||||
|
@ -14,7 +14,7 @@ BOOST_AUTO_TEST_CASE(test_vehicle_buoyancy) {
|
|||||||
BOOST_REQUIRE(vehicle != nullptr);
|
BOOST_REQUIRE(vehicle != nullptr);
|
||||||
|
|
||||||
BOOST_REQUIRE(vehicle->info != nullptr);
|
BOOST_REQUIRE(vehicle->info != nullptr);
|
||||||
BOOST_REQUIRE(vehicle->vehicle != nullptr);
|
BOOST_REQUIRE(vehicle->getVehicle() != nullptr);
|
||||||
|
|
||||||
// Relies on tile 0,0 being watered...
|
// Relies on tile 0,0 being watered...
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(test_activities) {
|
|||||||
VehicleObject* vehicle = Global::get().e->createVehicle(
|
VehicleObject* vehicle = Global::get().e->createVehicle(
|
||||||
90u, glm::vec3(10.f, 0.f, 0.f), glm::quat());
|
90u, glm::vec3(10.f, 0.f, 0.f), glm::quat());
|
||||||
BOOST_REQUIRE(vehicle != nullptr);
|
BOOST_REQUIRE(vehicle != nullptr);
|
||||||
BOOST_REQUIRE(vehicle->model != nullptr);
|
BOOST_REQUIRE(vehicle->getModel() != nullptr);
|
||||||
|
|
||||||
auto character = Global::get().e->createPedestrian(1, {0.f, 0.f, 0.f});
|
auto character = Global::get().e->createPedestrian(1, {0.f, 0.f, 0.f});
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
#include <data/WeaponData.hpp>
|
#include <data/WeaponData.hpp>
|
||||||
#include <loaders/GenericDATLoader.hpp>
|
#include <loaders/GenericDATLoader.hpp>
|
||||||
|
#include <objects/PickupObject.hpp>
|
||||||
|
#include <objects/InstanceObject.hpp>
|
||||||
#include "test_globals.hpp"
|
#include "test_globals.hpp"
|
||||||
|
|
||||||
// Tests against loading various data files
|
// Tests against loading various data files
|
||||||
@ -83,6 +85,42 @@ BOOST_AUTO_TEST_CASE(test_handling_data_loader) {
|
|||||||
BOOST_CHECK_EQUAL(handling.driveType, VehicleHandlingInfo::All);
|
BOOST_CHECK_EQUAL(handling.driveType, VehicleHandlingInfo::All);
|
||||||
BOOST_CHECK_EQUAL(handling.engineType, VehicleHandlingInfo::Petrol);
|
BOOST_CHECK_EQUAL(handling.engineType, VehicleHandlingInfo::Petrol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_model_files_loaded) {
|
||||||
|
auto& d = Global::get().d;
|
||||||
|
|
||||||
|
// The weapon models should be associated by the MODELFILE entries
|
||||||
|
auto ak47 = d->findModelInfo<SimpleModelInfo>(171);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(ak47->name, "ak47");
|
||||||
|
BOOST_CHECK_NE(ak47->getAtomic(0), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_model_archive_loaded) {
|
||||||
|
auto& d = Global::get().d;
|
||||||
|
auto& e = Global::get().e;
|
||||||
|
|
||||||
|
/// @todo Implement streaming
|
||||||
|
// Currently, instanciating an entity will load the model
|
||||||
|
{
|
||||||
|
auto crim = d->findModelInfo<PedModelInfo>(24);
|
||||||
|
auto pickup = e->createPickup({}, 24, PickupObject::InShop);
|
||||||
|
|
||||||
|
BOOST_REQUIRE(crim->type() == ModelDataType::PedInfo);
|
||||||
|
BOOST_CHECK_NE(crim->getModel(), nullptr);
|
||||||
|
|
||||||
|
e->destroyObject(pickup);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto info = d->findModelInfo<SimpleModelInfo>(2202);
|
||||||
|
auto inst = e->createInstance(2202, {});
|
||||||
|
|
||||||
|
BOOST_REQUIRE(info->type() == ModelDataType::SimpleInfo);
|
||||||
|
BOOST_CHECK_NE(info->getAtomic(0), nullptr);
|
||||||
|
|
||||||
|
e->destroyObject(inst);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
#include <data/Model.hpp>
|
#include <data/Model.hpp>
|
||||||
#include <job/WorkContext.hpp>
|
#include <job/WorkContext.hpp>
|
||||||
#include <loaders/BackgroundLoader.hpp>
|
|
||||||
#include "test_globals.hpp"
|
#include "test_globals.hpp"
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(LoaderDFFTests)
|
BOOST_AUTO_TEST_SUITE(LoaderDFFTests)
|
||||||
@ -38,31 +37,6 @@ BOOST_AUTO_TEST_CASE(test_load_dff) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_loader_job) {
|
|
||||||
{
|
|
||||||
WorkContext ctx;
|
|
||||||
|
|
||||||
ResourceHandle<Model>::Ref modelRef{
|
|
||||||
new ResourceHandle<Model>("landstal.dff")};
|
|
||||||
|
|
||||||
auto index = &Global::get().e->data->index;
|
|
||||||
auto job = new BackgroundLoaderJob<Model, LoaderDFF>{
|
|
||||||
&ctx, index, "landstal.dff", modelRef};
|
|
||||||
|
|
||||||
ctx.queueJob(job);
|
|
||||||
|
|
||||||
while (modelRef->state == RW::Loading) {
|
|
||||||
ctx.update();
|
|
||||||
std::this_thread::yield();
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_REQUIRE(modelRef->resource != nullptr);
|
|
||||||
|
|
||||||
BOOST_CHECK(modelRef->resource->frames.size() > 0);
|
|
||||||
|
|
||||||
delete modelRef->resource;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
#include <data/ObjectData.hpp>
|
#include <data/ModelData.hpp>
|
||||||
#include "test_globals.hpp"
|
#include "test_globals.hpp"
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(ObjectDataTests)
|
BOOST_AUTO_TEST_SUITE(ObjectDataTests)
|
||||||
@ -13,16 +13,16 @@ BOOST_AUTO_TEST_CASE(test_object_data) {
|
|||||||
|
|
||||||
BOOST_ASSERT(l.objects.find(1100) != l.objects.end());
|
BOOST_ASSERT(l.objects.find(1100) != l.objects.end());
|
||||||
|
|
||||||
auto obj = l.objects[1100];
|
auto obj = l.objects[1100].get();
|
||||||
|
|
||||||
auto def = std::dynamic_pointer_cast<ObjectData>(obj);
|
auto def = dynamic_cast<SimpleModelInfo*>(obj);
|
||||||
|
|
||||||
BOOST_ASSERT(def->class_type == ObjectInformation::_class("OBJS"));
|
BOOST_ASSERT(def->type() == ModelDataType::SimpleInfo);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(def->modelName, "rd_Corner1");
|
BOOST_CHECK_EQUAL(def->name, "rd_Corner1");
|
||||||
BOOST_CHECK_EQUAL(def->textureName, "generic");
|
BOOST_CHECK_EQUAL(def->textureslot, "generic");
|
||||||
BOOST_CHECK_EQUAL(def->numClumps, 1);
|
BOOST_CHECK_EQUAL(def->getNumAtomics(), 1);
|
||||||
BOOST_CHECK_EQUAL(def->drawDistance[0], 220);
|
BOOST_CHECK_EQUAL(def->getLodDistance(0), 220);
|
||||||
BOOST_CHECK_EQUAL(def->flags, 0);
|
BOOST_CHECK_EQUAL(def->flags, 0);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -32,21 +32,21 @@ BOOST_AUTO_TEST_CASE(test_object_data) {
|
|||||||
|
|
||||||
BOOST_ASSERT(l.objects.find(90) != l.objects.end());
|
BOOST_ASSERT(l.objects.find(90) != l.objects.end());
|
||||||
|
|
||||||
auto obj = l.objects[90];
|
auto obj = l.objects[90].get();
|
||||||
|
|
||||||
auto def = std::dynamic_pointer_cast<VehicleData>(obj);
|
auto def = dynamic_cast<VehicleModelInfo*>(obj);
|
||||||
|
|
||||||
BOOST_ASSERT(def->class_type == ObjectInformation::_class("CARS"));
|
BOOST_ASSERT(def->type() == ModelDataType::VehicleInfo);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(def->modelName, "landstal");
|
BOOST_CHECK_EQUAL(def->name, "landstal");
|
||||||
BOOST_CHECK_EQUAL(def->textureName, "landstal");
|
BOOST_CHECK_EQUAL(def->textureslot, "landstal");
|
||||||
BOOST_CHECK_EQUAL(def->type, VehicleData::CAR);
|
BOOST_CHECK_EQUAL(def->vehicletype_, VehicleModelInfo::CAR);
|
||||||
BOOST_CHECK_EQUAL(def->handlingID, "LANDSTAL");
|
BOOST_CHECK_EQUAL(def->handling_, "LANDSTAL");
|
||||||
BOOST_CHECK_EQUAL(def->gameName, "LANDSTK");
|
BOOST_CHECK_EQUAL(def->vehiclename_, "LANDSTK");
|
||||||
BOOST_CHECK_EQUAL(def->classType, VehicleData::RICHFAMILY);
|
BOOST_CHECK_EQUAL(def->vehicleclass_, VehicleModelInfo::RICHFAMILY);
|
||||||
BOOST_CHECK_EQUAL(def->frequency, 10);
|
BOOST_CHECK_EQUAL(def->frequency_, 10);
|
||||||
BOOST_CHECK_EQUAL(def->wheelModelID, 164);
|
BOOST_CHECK_EQUAL(def->wheelmodel_, 164);
|
||||||
BOOST_CHECK_CLOSE(def->wheelScale, 0.8f, 0.01f);
|
BOOST_CHECK_CLOSE(def->wheelscale_, 0.8f, 0.01f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(test_item_pickup) {
|
|||||||
BOOST_REQUIRE(item != nullptr);
|
BOOST_REQUIRE(item != nullptr);
|
||||||
|
|
||||||
ItemPickup* p = new ItemPickup(Global::get().e, {30.f, 0.f, 0.f},
|
ItemPickup* p = new ItemPickup(Global::get().e, {30.f, 0.f, 0.f},
|
||||||
PickupObject::OnStreet, item);
|
nullptr, PickupObject::OnStreet, item);
|
||||||
|
|
||||||
Global::get().e->allObjects.push_back(p);
|
Global::get().e->allObjects.push_back(p);
|
||||||
|
|
||||||
|
@ -14,10 +14,11 @@ BOOST_AUTO_TEST_CASE(test_create_vehicle) {
|
|||||||
BOOST_REQUIRE(vehicle != nullptr);
|
BOOST_REQUIRE(vehicle != nullptr);
|
||||||
|
|
||||||
BOOST_REQUIRE(vehicle->info != nullptr);
|
BOOST_REQUIRE(vehicle->info != nullptr);
|
||||||
BOOST_REQUIRE(vehicle->vehicle != nullptr);
|
BOOST_REQUIRE(vehicle->getVehicle() != nullptr);
|
||||||
|
|
||||||
// Hardcoded values for the moment
|
// Hardcoded values for the moment
|
||||||
BOOST_CHECK_EQUAL(vehicle->vehicle->type, VehicleData::CAR);
|
BOOST_CHECK_EQUAL(vehicle->getVehicle()->vehicletype_,
|
||||||
|
VehicleModelInfo::CAR);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(vehicle->info->wheels.size(), 4);
|
BOOST_CHECK_EQUAL(vehicle->info->wheels.size(), 4);
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ BOOST_AUTO_TEST_CASE(vehicle_parts) {
|
|||||||
Global::get().e->createVehicle(90u, glm::vec3(), glm::quat());
|
Global::get().e->createVehicle(90u, glm::vec3(), glm::quat());
|
||||||
|
|
||||||
BOOST_REQUIRE(vehicle != nullptr);
|
BOOST_REQUIRE(vehicle != nullptr);
|
||||||
BOOST_REQUIRE(vehicle->model != nullptr);
|
BOOST_REQUIRE(vehicle->getModel() != nullptr);
|
||||||
|
|
||||||
VehicleObject::Part* part = vehicle->getPart("bonnet_dummy");
|
VehicleObject::Part* part = vehicle->getPart("bonnet_dummy");
|
||||||
|
|
||||||
@ -51,7 +52,7 @@ BOOST_AUTO_TEST_CASE(vehicle_part_vis) {
|
|||||||
Global::get().e->createVehicle(90u, glm::vec3(), glm::quat());
|
Global::get().e->createVehicle(90u, glm::vec3(), glm::quat());
|
||||||
|
|
||||||
BOOST_REQUIRE(vehicle != nullptr);
|
BOOST_REQUIRE(vehicle != nullptr);
|
||||||
BOOST_REQUIRE(vehicle->model != nullptr);
|
BOOST_REQUIRE(vehicle->getModel() != nullptr);
|
||||||
|
|
||||||
VehicleObject::Part* bonnetpart = vehicle->getPart("bonnet_dummy");
|
VehicleObject::Part* bonnetpart = vehicle->getPart("bonnet_dummy");
|
||||||
auto skel = vehicle->skeleton;
|
auto skel = vehicle->skeleton;
|
||||||
@ -76,7 +77,7 @@ BOOST_AUTO_TEST_CASE(test_door_position) {
|
|||||||
BOOST_REQUIRE(vehicle != nullptr);
|
BOOST_REQUIRE(vehicle != nullptr);
|
||||||
|
|
||||||
BOOST_REQUIRE(vehicle->info != nullptr);
|
BOOST_REQUIRE(vehicle->info != nullptr);
|
||||||
BOOST_REQUIRE(vehicle->vehicle != nullptr);
|
BOOST_REQUIRE(vehicle->getVehicle() != nullptr);
|
||||||
|
|
||||||
BOOST_CHECK(vehicle->getSeatEntryPositionWorld(0).x > 5.f);
|
BOOST_CHECK(vehicle->getSeatEntryPositionWorld(0).x > 5.f);
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ BOOST_AUTO_TEST_CASE(TestWeaponScan) {
|
|||||||
// Test RADIUS scan
|
// Test RADIUS scan
|
||||||
auto character = Global::get().e->createPedestrian(1, {0.f, 0.f, 0.f});
|
auto character = Global::get().e->createPedestrian(1, {0.f, 0.f, 0.f});
|
||||||
BOOST_REQUIRE(character != nullptr);
|
BOOST_REQUIRE(character != nullptr);
|
||||||
BOOST_REQUIRE(character->model != nullptr);
|
BOOST_REQUIRE(character->getModel() != nullptr);
|
||||||
BOOST_REQUIRE(character->physObject != nullptr);
|
BOOST_REQUIRE(character->physObject != nullptr);
|
||||||
|
|
||||||
WeaponScan scan(10.f, {0.f, 0.f, 10.f}, {0.f, 0.f, -10.f});
|
WeaponScan scan(10.f, {0.f, 0.f, 10.f}, {0.f, 0.f, -10.f});
|
||||||
|
Loading…
Reference in New Issue
Block a user