1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-14 00:54:05 +02:00

#15 PSP port; C99 and gcc compatible; math optimizations; global refactoring;

This commit is contained in:
XProger
2018-01-24 09:54:11 +03:00
parent 37a162e2df
commit 1fb18ab819
31 changed files with 2528 additions and 924 deletions

View File

@@ -92,7 +92,7 @@ struct Animation {
// real frame index & lerp delta
int fIndex = int(time * 30.0f) / anim->frameRate;
int k = fIndex * anim->frameRate;
delta = (time * 30.0f - k) / min((int)anim->frameRate, framesCount - k); // min is because in some cases framesCount > realFramesCount / frameRate * frameRate
delta = (time * 30.0f - k) / min((int)anim->frameRate, max(1, framesCount - k)); // min is because in some cases framesCount > realFramesCount / frameRate * frameRate
// size of frame (in bytes)
int fIndexA = fIndex % fCount,
@@ -218,7 +218,9 @@ struct Animation {
return lerpAngle(frameA->getAngle(level->version, joint), frameB->getAngle(level->version, joint), delta);
}
Basis getJoints(Basis basis, int joint, bool postRot = false, Basis *joints = NULL) {
Basis getJoints(const mat4 &matrix, int joint, bool postRot = false, Basis *joints = NULL) {
mat4 basis = matrix;
ASSERT(model);
vec3 offset = isPrepareToNext ? this->offset : vec3(0.0f);
basis.translate(((vec3)frameA->pos).lerp(offset + frameB->pos, delta));
@@ -226,7 +228,7 @@ struct Animation {
TR::Node *node = (int)model->node < level->nodesDataSize ? (TR::Node*)&level->nodesData[model->node] : NULL;
int sIndex = 0;
Basis stack[16];
mat4 stack[16];
for (int i = 0; i < model->mCount; i++) {
@@ -236,7 +238,7 @@ struct Animation {
if (t.flags & 0x01) basis = stack[--sIndex];
if (t.flags & 0x02) stack[sIndex++] = basis;
ASSERT(sIndex >= 0 && sIndex < 16);
ASSERT(sIndex >= 0 && sIndex < COUNT(stack));
basis.translate(vec3((float)t.x, (float)t.y, (float)t.z));
}
@@ -249,7 +251,8 @@ struct Animation {
q = overrides[i];
else
q = getJointRot(i);
basis.rotate(q);
basis.setRot(basis.getRot() * q);
if (i == joint && postRot)
return basis;
@@ -257,6 +260,7 @@ struct Animation {
if (joints)
joints[i] = basis;
}
return basis;
}

View File

@@ -15,6 +15,7 @@
//#define WATER_USE_GRID
#define UNDERWATER_COLOR "#define UNDERWATER_COLOR vec3(0.6, 0.9, 0.9)\n"
#ifndef FFP
const char SHADER[] =
#include "shaders/shader.glsl"
;
@@ -30,6 +31,7 @@ const char FILTER[] =
const char GUI[] =
#include "shaders/gui.glsl"
;
#endif
struct ShaderCache {
enum Effect { FX_NONE = 0, FX_UNDERWATER = 1, FX_ALPHA_TEST = 2, FX_CLIP_PLANE = 4 };
@@ -114,6 +116,7 @@ struct ShaderCache {
}
Shader* compile(Core::Pass pass, Shader::Type type, int fx) {
#ifndef FFP
char def[1024], ext[255];
ext[0] = 0;
if (Core::settings.detail.shadows) {
@@ -142,6 +145,11 @@ struct ShaderCache {
src = SHADER;
typ = typeNames[type];
sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define MAX_CONTACTS %d\n#define FOG_DIST (1.0/%d.0)\n#define WATER_FOG_DIST (1.0/%d.0)\n#define SHADOW_TEX_SIZE %d.0\n", ext, passNames[pass], typ, MAX_LIGHTS, MAX_ANIM_TEX_RANGES, MAX_ANIM_TEX_OFFSETS, MAX_CONTACTS, FOG_DIST, WATER_FOG_DIST, SHADOW_TEX_SIZE);
#ifdef MERGE_SPRITES
if (type == Shader::SPRITE)
strcat(def, "#define ALIGN_SPRITES 1\n");
#endif
if (fx & FX_UNDERWATER) strcat(def, "#define UNDERWATER\n" UNDERWATER_COLOR);
if (fx & FX_ALPHA_TEST) strcat(def, "#define ALPHA_TEST\n");
if (pass == Core::passCompose) {
@@ -190,10 +198,14 @@ struct ShaderCache {
}
LOG("shader: compile %s -> %s %s%s%s\n", passNames[pass], typ, (fx & FX_UNDERWATER) ? "underwater " : "", (fx & FX_ALPHA_TEST) ? "alphaTest " : "", (fx & FX_CLIP_PLANE) ? "clipPlane" : "");
return shaders[pass][type][fx] = new Shader(src, def);
#else
return NULL;
#endif
}
void bind(Core::Pass pass, Shader::Type type, int fx, IGame *game) {
Core::pass = pass;
#ifndef FFP
Shader *shader = shaders[pass][type][fx];
if (!shader)
shader = compile(pass, type, fx);
@@ -209,6 +221,7 @@ struct ShaderCache {
ASSERT(mesh->animTexOffsetsCount <= MAX_ANIM_TEX_OFFSETS);
shader->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
shader->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
#endif
}
};
@@ -306,7 +319,7 @@ struct AmbientCache {
// get result color from 1x1 textures
for (int j = 0; j < 6; j++) {
Core::setTarget(textures[j * 4 + 3]);
colors[j] = Core::copyPixel(0, 0).xyz;
colors[j] = Core::copyPixel(0, 0).xyz();
}
Core::setDepthTest(true);
@@ -435,7 +448,7 @@ struct WaterCache {
#ifdef BLUR_CAUSTICS
caustics_tmp = Core::settings.detail.water > Core::Settings::MEDIUM ? new Texture(512, 512, Texture::RGBA) : NULL;
#endif
mask = new Texture(w, h, Texture::RGB16, false, m, false);
mask = new Texture(w, h, Texture::RGB16, Texture::NEAREST, m);
delete[] m;
blank = false;

View File

@@ -6,7 +6,7 @@
#include "controller.h"
#include "character.h"
#define CAMERA_OFFSET (1024.0f + 256.0f)
#define CAMERA_OFFSET (1024.0f + 512.0f)
struct Camera : ICamera {
@@ -154,7 +154,7 @@ struct Camera : ICamera {
if (!firstPerson || viewIndex != -1)
return false;
Basis head = owner->animation.getJoints(owner->getMatrix(), 14, true);
Basis head = owner->getJoint(owner->jointHead);
Basis eye(quat(0.0f, 0.0f, 0.0f, 1.0f), vec3(0.0f, -40.0f, 10.0f));
eye = head * eye;
mViewInv.identity();
@@ -347,16 +347,14 @@ struct Camera : ICamera {
Core::mView.translate(vec3(0.0f, sinf(shake * PI * 7) * shake * 48.0f, 0.0f));
if (Core::settings.detail.stereo)
Core::mView.translate(Core::mViewInv.right.xyz * (-Core::eye * (firstPerson ? 8.0f : 32.0f) ));
Core::mView.translate(Core::mViewInv.right().xyz() * (-Core::eye * (firstPerson ? 8.0f : 32.0f) ));
Core::mProj = getProjMatrix();
// TODO: temporal anti-aliasing
// Core::mProj.e02 = (randf() - 0.5f) * 32.0f / Core::width;
// Core::mProj.e12 = (randf() - 0.5f) * 32.0f / Core::height;
}
Core::mViewProj = Core::mProj * Core::mView;
Core::viewPos = Core::mViewInv.offset.xyz;
Core::setViewProj(Core::mView, Core::mProj);
Core::viewPos = Core::mViewInv.offset().xyz();
frustum->pos = Core::viewPos;
frustum->calcPlanes(Core::mViewProj);
@@ -373,6 +371,9 @@ struct Camera : ICamera {
fov = firstPerson ? 90.0f : 65.0f;
znear = firstPerson ? 8.0f : 32.0f;
#ifdef _PSP
znear = 256.0f;
#endif
zfar = 45.0f * 1024.0f;
}
};

View File

@@ -216,7 +216,16 @@ struct Character : Controller {
}
vec3 getViewPoint() {
return animation.getJoints(getMatrix(), jointChest).pos;
/*
Box box = getBoundingBoxLocal();
vec3 p = pos;
float delta = (box.max.z + box.min.z) * 0.5f;
p.x += sinf(angle.y) * delta;
p.z += cosf(angle.y) * delta;
p.y += box.max.y + (box.min.y - box.max.y) * 0.75f;
return p;
*/
return getJoint(jointChest).pos;
}
virtual void lookAt(Controller *target) {

View File

@@ -24,10 +24,10 @@ struct Collision {
int q = angleQuadrant(angle);
const vec2 v[] = {
{ -radius, radius },
{ radius, radius },
{ radius, -radius },
{ -radius, -radius },
vec2( -radius, radius ),
vec2( radius, radius ),
vec2( radius, -radius ),
vec2( -radius, -radius ),
};
const vec2 &l = v[q], &r = v[(q + 1) % 4];

View File

@@ -39,6 +39,7 @@ struct IGame {
virtual TR::Level* getLevel() { return NULL; }
virtual MeshBuilder* getMesh() { return NULL; }
virtual Texture* getAtlas() { return NULL; }
virtual ICamera* getCamera() { return NULL; }
virtual Controller* getLara() { return NULL; }
virtual bool isCutscene() { return false; }
@@ -53,7 +54,7 @@ struct IGame {
virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0, Core::Pass pass = Core::passAmbient) {}
virtual void renderCompose(int roomIndex) {}
virtual void renderView(int roomIndex, bool water) {}
virtual void setEffect(Controller *controller, TR::Effect effect) {}
virtual void setEffect(Controller *controller, TR::Effect::Type effect) {}
virtual void checkTrigger(Controller *controller, bool heavy) {}
@@ -89,7 +90,7 @@ struct Controller {
TR::Entity::Flags flags;
Basis *joints;
int frameIndex;
int jointsFrame;
vec3 ambient[6];
float specular;
@@ -129,8 +130,9 @@ struct Controller {
fixRoomIndex();
const TR::Model *m = getModel();
joints = m ? new Basis[m->mCount] : NULL;
frameIndex = -1;
joints = m ? new Basis[m->mCount] : NULL;
jointsFrame = -1;
specular = 0.0f;
intensity = e.intensity == -1 ? -1.0f : intensityf(e.intensity);
timer = 0.0f;
@@ -152,6 +154,7 @@ struct Controller {
if (e.isLara() || e.isActor()) // Lara and cutscene entities is active by default
activate();
updated = false;
}
virtual ~Controller() {
@@ -369,7 +372,7 @@ struct Controller {
}
case TR::FloorData::TRIGGER : {
info.trigger = (TR::Level::Trigger)cmd.sub;
info.trigger = (TR::Level::Trigger::Type)cmd.sub;
info.trigCmdCount = 0;
info.trigInfo = (*fd++).triggerInfo;
TR::FloorData::TriggerCommand trigCmd;
@@ -558,7 +561,8 @@ struct Controller {
Box box = target->getBoundingBox();
vec3 t = (box.min + box.max) * 0.5f;
Basis b = animation.getJoints(Basis(getMatrix()), joint);
updateJoints();
Basis b = animation.getJoints(getMatrix(), joint);
vec3 delta = (b.inverse() * t).normal();
if (invertAim)
delta = -delta;
@@ -617,7 +621,7 @@ struct Controller {
}
virtual vec3 getPos() {
return getEntity().isActor() ? animation.getJoints(getMatrix(), 0).pos : pos;
return getEntity().isActor() ? getJoint(0).pos : pos;
}
vec3 getDir() const {
@@ -679,13 +683,13 @@ struct Controller {
const TR::Model *m = getModel();
ASSERT(m->mCount <= MAX_SPHERES);
Basis basis(getMatrix());
// TODO: optimize (check frame index for animation updates, use joints array)
updateJoints();
count = 0;
for (int i = 0; i < m->mCount; i++) {
TR::Mesh &aMesh = level->meshes[level->meshOffsets[m->mStart + i]];
if (aMesh.radius <= 0) continue;
vec3 center = animation.getJoints(basis, i, true) * aMesh.center;
vec3 center = joints[i] * aMesh.center;
spheres[count++] = Sphere(center, aMesh.radius);
}
}
@@ -863,14 +867,14 @@ struct Controller {
if (cmd == TR::ANIM_CMD_EFFECT) {
switch (fx) {
case TR::Effect::ROTATE_180 : angle.y = angle.y + PI; break;
case TR::Effect::FLOOR_SHAKE : game->setEffect(this, TR::Effect(fx)); break;
case TR::Effect::FLOOR_SHAKE : game->setEffect(this, TR::Effect::Type(fx)); break;
case TR::Effect::FINISH_LEVEL : game->loadNextLevel(); break;
case TR::Effect::FLIP_MAP : level->state.flags.flipped = !level->state.flags.flipped; break;
default : cmdEffect(fx); break;
}
} else {
if (!(sfx & 0x8000)) { // TODO 0x4000 / 0x8000 for ground / water foot steps
game->playSound(fx, pos, Sound::Flags::PAN);
game->playSound(fx, pos, Sound::PAN);
}
}
}
@@ -1028,7 +1032,8 @@ struct Controller {
explodeParts = new ExplodePart[model->mCount];
explodeMask = 0;
animation.getJoints(getMatrix(), -1, true, joints);
updateJoints();
int roomIndex = getRoomIndex();
for (int i = 0; i < model->mCount; i++) {
if (!(mask & (1 << i)))
@@ -1066,27 +1071,44 @@ struct Controller {
mat4 m;
m.identity();
m.dir = vec4(dir * size.z, 0.0f);
m.up = vec4(up, 0.0f);
m.right = vec4(right * size.x, 0.0f);
m.offset = vec4(center.x, info.floor - 8.0f, center.z, 1.0f);
m.dir() = vec4(dir * size.z, 0.0f);
m.up() = vec4(up, 0.0f);
m.right() = vec4(right * size.x, 0.0f);
m.offset() = vec4(center.x, info.floor - 8.0f, center.z, 1.0f);
Core::mModel = m;
Basis b;
b.identity();
game->setShader(Core::pass, Shader::FLASH, false, false);
Core::active.shader->setParam(uViewProj, Core::mViewProj * m);
Core::active.shader->setParam(uBasis, b);
Core::setBasis(&b, 1);
float alpha = lerp(0.7f, 0.90f, clamp((info.floor - boxA.max.y) / 1024.0f, 0.0f, 1.0f) );
Core::active.shader->setParam(uMaterial, vec4(vec3(0.5f * (1.0f - alpha)), alpha));
float lum = 0.5f * (1.0f - alpha);
Core::setMaterial(lum, lum, lum, alpha);
Core::active.shader->setParam(uAmbient, vec3(0.0f));
Core::setDepthWrite(false);
mesh->renderShadowBlob();
Core::setDepthWrite(true);
}
bool updated;
void updateJoints() {
//if (updated) return;
if (Core::stats.frame == jointsFrame)
return;
animation.getJoints(getMatrix(), -1, true, joints);
jointsFrame = Core::stats.frame;
updated = true;
}
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) { // TODO: animation.calcJoints
Basis& getJoint(int index) {
updateJoints();
return joints[index];
}
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
mat4 matrix = getMatrix();
Box box = animation.getBoundingBox(vec3(0, 0, 0), 0);
@@ -1098,8 +1120,9 @@ struct Controller {
flags.rendered = true;
if (Core::stats.frame != frameIndex)
animation.getJoints(matrix, -1, true, joints);
updateJoints();
Core::mModel = getMatrix();
if (layers) {
uint32 mask = 0;
@@ -1111,7 +1134,7 @@ struct Controller {
mask |= layers[i].mask;
// set meshes visibility
for (int j = 0; j < model->mCount; j++)
joints[j].w = (vmask & (1 << j)) ? 1.0f : -1.0f; // AHAHA
joints[j].w = (vmask & (1 << j)) ? 1.0f : -1.0f; // hide invisible parts
if (explodeMask) {
ASSERT(explodeParts);
@@ -1121,18 +1144,14 @@ struct Controller {
joints[i] = explodeParts[i].basis;
}
// if (entity.type == TR::Entity::LARA && Core::eye != 0)
// joints[14].w = -1.0f;
// render
Core::active.shader->setParam(uBasis, joints[0], model->mCount);
mesh->renderModel(layers[i].model);
Core::setBasis(joints, model->mCount);
mesh->renderModel(layers[i].model, caustics);
}
} else {
Core::active.shader->setParam(uBasis, joints[0], model->mCount);
mesh->renderModel(getEntity().modelIndex - 1);
Core::setBasis(joints, model->mCount);
mesh->renderModel(getEntity().modelIndex - 1, caustics);
}
frameIndex = Core::stats.frame;
}
};

View File

@@ -1,7 +1,9 @@
#ifndef H_CORE
#define H_CORE
#define USE_INFLATE
#ifndef _PSP
#define USE_INFLATE
#endif
#include <stdio.h>
#ifdef WIN32
@@ -137,12 +139,31 @@
#define glGetProgramBinary(...)
#define glProgramBinary(...)
#elif _PSP
#include <pspgu.h>
#include <pspgum.h>
#define FFP
//#define TEX_SWIZZLE
#define EDRAM_MESH
//#define EDRAM_TEX
#endif
#ifdef USE_INFLATE
#include "libs/tinf/tinf.h"
#endif
#ifdef FFP
#define SPLIT_BY_TILE
#ifdef _PSP
#define SPLIT_BY_CLUT
#endif
#else
#define MERGE_MODELS
#define MERGE_SPRITES
#define GENERATE_WATER_PLANE
#endif
#include "utils.h"
enum ControlKey { cLeft, cRight, cUp, cDown, cJump, cWalk, cAction, cWeapon, cLook, cStepLeft, cStepRight, cRoll, cInventory, cMAX };
@@ -164,6 +185,9 @@ enum InputKey { ikNone,
struct KeySet {
InputKey key, joy;
KeySet() {}
KeySet(InputKey key, InputKey joy) : key(key), joy(joy) {}
};
namespace Core {
@@ -171,7 +195,7 @@ namespace Core {
int lastTime;
int width, height;
struct {
struct Support {
int maxVectors;
int maxAniso;
bool shaderBinary;
@@ -191,7 +215,7 @@ namespace Core {
} support;
struct Settings {
enum Quality : uint8 { LOW, MEDIUM, HIGH };
enum Quality { LOW, MEDIUM, HIGH };
struct {
union {
@@ -363,7 +387,7 @@ namespace Core {
struct Shader;
struct Texture;
enum RenderState : int32 {
enum RenderState {
RS_TARGET = 1 << 0,
RS_VIEWPORT = 1 << 1,
RS_DEPTH_TEST = 1 << 2,
@@ -383,7 +407,7 @@ enum RenderState : int32 {
RS_BLEND = RS_BLEND_ADD | RS_BLEND_ALPHA | RS_BLEND_MULT | RS_BLEND_PREMULT,
};
typedef unsigned short Index;
typedef uint16 Index;
struct Vertex {
short4 coord; // xyz - position, w - joint index (for entities only)
@@ -394,6 +418,31 @@ struct Vertex {
ubyte4 light; // xyz - color, w - use premultiplied alpha
};
#ifdef FFP
#ifdef _PSP
struct VertexGPU {
short2 texCoord;
ubyte4 color;
short3 normal;
short3 coord;
};
#else
/*
struct VertexGPU {
short2 texCoord;
ubyte4 color;
short3 normal;
uint16 _alignN;
short3 coord;
uint16 _alignC;
};
*/
typedef Vertex VertexGPU;
#endif
#else
typedef Vertex VertexGPU;
#endif
#ifdef PROFILE
//#define USE_CV_MARKERS
@@ -470,7 +519,7 @@ enum BlendMode { bmNone, bmAlpha, bmAdd, bmMult, bmPremult };
namespace Core {
float eye;
vec4 viewport, viewportDef;
mat4 mView, mProj, mViewProj, mViewInv, mLightProj;
mat4 mModel, mView, mProj, mViewProj, mViewInv, mLightProj;
Basis basis;
vec3 viewPos;
vec4 lightPos[MAX_LIGHTS];
@@ -482,33 +531,46 @@ namespace Core {
enum Pass { passCompose, passShadow, passAmbient, passWater, passFilter, passGUI, passMAX } pass;
GLuint FBO, defaultFBO;
#ifdef _PSP
void *curBackBuffer;
#else
GLuint FBO, defaultFBO;
struct RenderTargetCache {
int count;
struct Item {
GLuint ID;
int width;
int height;
} items[MAX_RENDER_BUFFERS];
} rtCache[2];
#endif
Texture *defaultTarget;
int32 renderState;
struct RenderTargetCache {
int count;
struct Item {
GLuint ID;
int width;
int height;
} items[MAX_RENDER_BUFFERS];
} rtCache[2];
int32 renderState;
struct {
struct Active {
Shader *shader;
Texture *textures[8];
Texture *target;
int targetFace;
vec4 viewport;
vec4 material;
uint32 targetFace;
#ifdef _PSP
Index *iBuffer;
VertexGPU *vBuffer;
#else
GLuint VAO;
GLuint iBuffer;
GLuint vBuffer;
#endif
int32 renderState;
int32 basisCount;
Basis *basis;
} active;
struct {
struct ReqTarget {
Texture *texture;
bool clear;
uint8 face;
@@ -539,6 +601,45 @@ namespace Core {
frame++;
}
} stats;
#ifdef _PSP
uint32 *cmdBuf = NULL;
static int EDRAM_OFFSET;
static int EDRAM_SIZE;
void* allocEDRAM(int size) {
LOG("EDRAM ALLOC: offset: %d size %d\n", Core::EDRAM_OFFSET, size);
if (Core::EDRAM_OFFSET + size > EDRAM_SIZE)
LOG("! EDRAM overflow !\n");
void *ptr = ((char*)sceGeEdramGetAddr()) + EDRAM_OFFSET;
EDRAM_OFFSET += (size + 15) / 16 * 16;
return ptr;
}
void freeEDRAM() {
EDRAM_OFFSET = (512 * 272 * 2 * 2) + (512 * 272 * 2);
LOG("EDRAM FREE: offset: %d\n", EDRAM_OFFSET);
}
#endif
void beginCmdBuf() {
#ifdef _PSP
if (!cmdBuf)
cmdBuf = new uint32[262144];
sceGuStart(GU_DIRECT, cmdBuf);
#endif
}
void submitCmdBuf() {
#ifdef _PSP
ASSERT(cmdBuf);
sceGuFinish();
sceGuSync(GU_SYNC_WAIT, GU_SYNC_FINISH);
#endif
}
}
#include "texture.h"
@@ -632,6 +733,16 @@ namespace Core {
GetProcOGL(glProgramBinary);
#endif
const char *vendor, *renderer, *version;
#ifdef _PSP
vendor = "Sony";
renderer = "SCE GU";
version = "1.0";
#else
vendor = (char*)glGetString(GL_VENDOR);
renderer = (char*)glGetString(GL_RENDERER);
version = (char*)glGetString(GL_VERSION);
char *ext = (char*)glGetString(GL_EXTENSIONS);
/*
@@ -648,8 +759,27 @@ namespace Core {
}
}
*/
glGetIntegerv(GL_MAX_VARYING_VECTORS, &support.maxVectors);
#endif
#ifdef FFP
support.maxAniso = 1;
support.maxVectors = 0;
support.shaderBinary = false;
support.VAO = false;
support.depthTexture = false;
support.shadowSampler = false;
support.discardFrame = false;
support.texNPOT = false;
support.texRG = false;
support.texBorder = false;
support.maxAniso = false;
support.colorFloat = false;
support.colorHalf = false;
support.texFloatLinear = false;
support.texFloat = false;
support.texHalfLinear = false;
support.texHalf = false;
#else
support.shaderBinary = extSupport(ext, "_program_binary");
support.VAO = extSupport(ext, "_vertex_array_object");
support.depthTexture = extSupport(ext, "_depth_texture");
@@ -668,16 +798,22 @@ namespace Core {
if (support.maxAniso)
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &support.maxAniso);
glGetIntegerv(GL_MAX_VARYING_VECTORS, &support.maxVectors);
#endif
#ifdef PROFILE
support.profMarker = extSupport(ext, "_KHR_debug");
support.profTiming = extSupport(ext, "_timer_query");
#endif
char *vendor = (char*)glGetString(GL_VENDOR);
LOG("Vendor : %s\n", vendor);
LOG("Renderer : %s\n", glGetString(GL_RENDERER));
LOG("Version : %s\n", glGetString(GL_VERSION));
LOG("Renderer : %s\n", renderer);
LOG("Version : %s\n", version);
LOG("cache : %s\n", Stream::cacheDir);
#ifdef _PSP
EDRAM_SIZE = sceGeEdramGetSize();
LOG("VRAM : %d\n", EDRAM_SIZE);
#endif
LOG("supports :\n");
LOG(" variyngs count : %d\n", support.maxVectors);
LOG(" binary shaders : %s\n", support.shaderBinary ? "true" : "false");
@@ -694,13 +830,89 @@ namespace Core {
support.colorHalf ? "full" : (support.texHalf ? (support.texHalfLinear ? "linear" : "nearest") : "false"));
LOG("\n");
#ifdef FFP
#ifdef _PSP
Core::width = 480;
Core::height = 272;
sceGuDepthFunc(GU_LEQUAL);
sceGuDepthRange(0x0000, 0xFFFF);
sceGuClearDepth(0xFFFF);
sceGuShadeModel(GU_SMOOTH);
sceGuAlphaFunc(GU_GREATER, 127, 255);
sceGuEnable(GU_ALPHA_TEST);
int swizzle = GU_FALSE;
#ifdef TEX_SWIZZLE
swizzle = GU_TRUE;
#endif
sceGuClutMode(GU_PSM_5551, 0, 0xFF, 0);
sceGuTexMode(GU_PSM_T4, 0, 0, swizzle);
sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
sceGuTexScale(1.0f, 1.0f);
sceGuTexOffset(0.0f, 0.0f);
sceGuTexFilter(GU_LINEAR, GU_LINEAR);
//sceGuTexFilter(GU_NEAREST, GU_NEAREST);
sceGuEnable(GU_CLIP_PLANES);
const ScePspIMatrix4 dith =
{ {-4, 0, -3, 1},
{ 2, -2, 3, -1},
{-3, 1, -4, 0},
{ 3, -1, 2, -2} };
sceGuSetDither(&dith);
sceGuEnable(GU_DITHER);
sceGuEnable(GU_LIGHT0);
sceGuDisable(GU_LIGHT1);
sceGuDisable(GU_LIGHT2);
sceGuDisable(GU_LIGHT3);
sceGuAmbientColor(0xFFFFFFFF);
sceGuColor(0xFFFFFFFF);
freeEDRAM();
#else
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glClearColor(0.5, 0.5, 0.5, 1);
glAlphaFunc(GL_GREATER, 0.5f);
glEnable(GL_ALPHA_TEST);
glEnable(GL_LIGHT0);
glDisable(GL_LIGHT1);
glDisable(GL_LIGHT2);
glDisable(GL_LIGHT3);
glEnable(GL_NORMALIZE);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glScalef(1.0f / 32767.0f, 1.0f / 32767.0f, 1.0f / 32767.0f);
#endif
#endif
#ifndef _PSP
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&defaultFBO);
glGenFramebuffers(1, &FBO);
memset(rtCache, 0, sizeof(rtCache));
defaultTarget = NULL;
glDepthFunc(GL_LEQUAL);
memset(rtCache, 0, sizeof(rtCache));
#endif
#if defined(FFP) && defined(SPLIT_BY_TILE)
#ifdef _PSP
sceGuEnable(GU_TEXTURE_2D);
#else
glEnable(GL_TEXTURE_2D);
#endif
#endif
defaultTarget = NULL;
Sound::init();
for (int i = 0; i < MAX_LIGHTS; i++) {
@@ -710,9 +922,9 @@ namespace Core {
eye = 0.0f;
uint32 data = 0x00000000;
blackTex = new Texture(1, 1, Texture::RGBA, false, &data, false);
blackTex = new Texture(1, 1, Texture::RGBA, Texture::NEAREST, &data);
data = 0xFFFFFFFF;
whiteTex = new Texture(1, 1, Texture::RGBA, false, &data, false);
whiteTex = new Texture(1, 1, Texture::RGBA, Texture::NEAREST, &data);
// init settings
settings.detail.setFilter (Core::Settings::HIGH);
@@ -729,33 +941,45 @@ namespace Core {
settings.controls.multitarget = true;
settings.controls.vibration = true;
settings.controls.keys[ cLeft ] = { ikLeft, ikJoyLeft };
settings.controls.keys[ cRight ] = { ikRight, ikJoyRight };
settings.controls.keys[ cUp ] = { ikUp, ikJoyUp };
settings.controls.keys[ cDown ] = { ikDown, ikJoyDown };
settings.controls.keys[ cLeft ] = KeySet( ikLeft, ikJoyLeft );
settings.controls.keys[ cRight ] = KeySet( ikRight, ikJoyRight );
settings.controls.keys[ cUp ] = KeySet( ikUp, ikJoyUp );
settings.controls.keys[ cDown ] = KeySet( ikDown, ikJoyDown );
#ifdef __EMSCRIPTEN__
settings.controls.keys[ cJump ] = { ikD, ikJoyX };
settings.controls.keys[ cJump ] = KeySet( ikD, ikJoyX );
#else
settings.controls.keys[ cJump ] = { ikAlt, ikJoyX };
settings.controls.keys[ cJump ] = KeySet( ikAlt, ikJoyX );
#endif
settings.controls.keys[ cWalk ] = { ikShift, ikJoyRB };
settings.controls.keys[ cAction ] = { ikCtrl, ikJoyA };
settings.controls.keys[ cWeapon ] = { ikSpace, ikJoyY };
settings.controls.keys[ cLook ] = { ikC, ikJoyLB };
settings.controls.keys[ cStepLeft ] = { ikZ, ikJoyLT };
settings.controls.keys[ cStepRight ] = { ikX, ikJoyRT };
settings.controls.keys[ cRoll ] = { ikA, ikJoyB };
settings.controls.keys[ cInventory ] = { ikTab, ikJoySelect };
settings.controls.keys[ cWalk ] = KeySet( ikShift, ikJoyRB );
settings.controls.keys[ cAction ] = KeySet( ikCtrl, ikJoyA );
settings.controls.keys[ cWeapon ] = KeySet( ikSpace, ikJoyY );
settings.controls.keys[ cLook ] = KeySet( ikC, ikJoyLB );
settings.controls.keys[ cStepLeft ] = KeySet( ikZ, ikJoyLT );
settings.controls.keys[ cStepRight ] = KeySet( ikX, ikJoyRT );
settings.controls.keys[ cRoll ] = KeySet( ikA, ikJoyB );
settings.controls.keys[ cInventory ] = KeySet( ikTab, ikJoySelect );
#ifdef __RPI__
#ifdef __RPI__
settings.detail.setShadows(Core::Settings::LOW);
#endif
#endif
#ifdef FFP
settings.detail.setFilter (Core::Settings::MEDIUM);
settings.detail.setLighting (Core::Settings::LOW);
settings.detail.setShadows (Core::Settings::LOW);
settings.detail.setWater (Core::Settings::LOW);
settings.audio.reverb = false;
#endif
resetTime();
}
void deinit() {
delete blackTex;
delete whiteTex;
#ifdef _PSP
delete[] cmdBuf;
#else
/*
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFrameBuffers(1, &FBO);
@@ -765,9 +989,11 @@ namespace Core {
for (int i = 0; i < rtCache[b].count; i++)
glDeleteRenderBuffers(1, &rtCache[b].items[i].ID);
*/
#endif
Sound::deinit();
}
#ifndef _PSP
int cacheRenderTarget(bool depth, int width, int height) {
RenderTargetCache &cache = rtCache[depth];
@@ -778,17 +1004,16 @@ namespace Core {
ASSERT(cache.count < MAX_RENDER_BUFFERS);
RenderTargetCache::Item &item = cache.items[cache.count];
glGenRenderbuffers(1, &item.ID);
item.width = width;
item.height = height;
glGenRenderbuffers(1, &item.ID);
glBindRenderbuffer(GL_RENDERBUFFER, item.ID);
glRenderbufferStorage(GL_RENDERBUFFER, depth ? GL_RGB565 : GL_DEPTH_COMPONENT16, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
return cache.count++;
}
#endif
bool update() {
resetState = false;
@@ -809,12 +1034,19 @@ namespace Core {
uint8 face = reqTarget.face;
if (target != active.target || face != active.targetFace) {
#ifdef _PSP
/*
if (!target)
sceGuDrawBufferList(GU_PSM_5650, curBackBuffer, 512);
else
sceGuDrawBufferList(GU_PSM_5650, target->offset, target->width);
*/
#else
if (!target) { // may be a null
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
} else {
GLenum texTarget = GL_TEXTURE_2D;
if (target->cube)
if (target->opt & Texture::CUBEMAP)
texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
bool depth = target->format == Texture::DEPTH || target->format == Texture::SHADOW;
@@ -824,6 +1056,7 @@ namespace Core {
glFramebufferTexture2D (GL_FRAMEBUFFER, depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, texTarget, target->ID, 0);
glFramebufferRenderbuffer (GL_FRAMEBUFFER, depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rtCache[depth].items[rtIndex].ID);
}
#endif
active.target = target;
active.targetFace = face;
@@ -833,30 +1066,62 @@ namespace Core {
if (mask & RS_VIEWPORT) {
if (viewport != active.viewport) {
active.viewport = viewport;
#ifdef _PSP
sceGuOffset(2048 - int(viewport.z) / 2, 2048 - int(viewport.w) / 2);
sceGuViewport(2048 + int(viewport.x), 2048 + int(viewport.y), int(viewport.z), int(viewport.w));
#else
glViewport(int(viewport.x), int(viewport.y), int(viewport.z), int(viewport.w));
#endif
}
renderState &= ~RS_VIEWPORT;
}
if (mask & RS_DEPTH_TEST) {
#ifdef _PSP
if (renderState & RS_DEPTH_TEST)
sceGuEnable(GU_DEPTH_TEST);
else
sceGuDisable(GU_DEPTH_TEST);
#else
if (renderState & RS_DEPTH_TEST)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
#endif
}
if (mask & RS_DEPTH_WRITE) {
glDepthMask((renderState & RS_DEPTH_WRITE) != 0);
#ifdef _PSP
sceGuDepthMask((renderState & RS_DEPTH_WRITE) != 0 ? GU_FALSE : GU_TRUE);
#else
glDepthMask((renderState & RS_DEPTH_WRITE) != 0 ? GL_TRUE : GL_FALSE);
#endif
}
if (mask & RS_COLOR_WRITE) {
#ifdef _PSP
sceGuPixelMask(~(((renderState & RS_COLOR_WRITE_R) != 0 ? 0x000000FF : 0) |
((renderState & RS_COLOR_WRITE_G) != 0 ? 0x0000FF00 : 0) |
((renderState & RS_COLOR_WRITE_B) != 0 ? 0x00FF0000 : 0) |
((renderState & RS_COLOR_WRITE_A) != 0 ? 0xFF000000 : 0)));
#else
glColorMask((renderState & RS_COLOR_WRITE_R) != 0,
(renderState & RS_COLOR_WRITE_G) != 0,
(renderState & RS_COLOR_WRITE_B) != 0,
(renderState & RS_COLOR_WRITE_A) != 0);
#endif
}
if (mask & RS_CULL) {
#ifdef _PSP
if (!(active.renderState & RS_CULL))
sceGuEnable(GU_CULL_FACE);
switch (renderState & RS_CULL) {
case RS_CULL_BACK : sceGuFrontFace(GU_CCW); break;
case RS_CULL_FRONT : sceGuFrontFace(GU_CW); break;
default : sceGuDisable(GU_CULL_FACE);
}
#else
if (!(active.renderState & RS_CULL))
glEnable(GL_CULL_FACE);
switch (renderState & RS_CULL) {
@@ -864,9 +1129,21 @@ namespace Core {
case RS_CULL_FRONT : glCullFace(GL_FRONT); break;
default : glDisable(GL_CULL_FACE);
}
#endif
}
if (mask & RS_BLEND) {
#ifdef _PSP
if (!(active.renderState & RS_BLEND))
sceGuEnable(GU_BLEND);
switch (renderState & RS_BLEND) {
case RS_BLEND_ALPHA : sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); break;
case RS_BLEND_ADD : sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, 0xffffffff, 0xffffffff); break;
case RS_BLEND_MULT : sceGuBlendFunc(GU_ADD, GU_DST_COLOR, GU_FIX, 0, 0); break;
case RS_BLEND_PREMULT : sceGuBlendFunc(GU_ADD, GU_FIX, GU_ONE_MINUS_SRC_ALPHA, 0xffffffff, 0); break;
default : sceGuDisable(GU_BLEND);
}
#else
if (!(active.renderState & RS_BLEND))
glEnable(GL_BLEND);
switch (renderState & RS_BLEND) {
@@ -876,11 +1153,17 @@ namespace Core {
case RS_BLEND_PREMULT : glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); break;
default : glDisable(GL_BLEND);
}
#endif
}
if (mask & RS_TARGET) { // for cler the RT & reset mask
if (reqTarget.clear)
if (mask & RS_TARGET) {
if (reqTarget.clear) {
#ifdef _PSP
sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT | GU_FAST_CLEAR_BIT);
#else
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
#endif
}
renderState &= ~RS_TARGET;
}
@@ -888,7 +1171,15 @@ namespace Core {
}
void setClearColor(const vec4 &color) {
#ifdef _PSP
ubyte4 c(clamp(int(color.x * 255), 0, 255),
clamp(int(color.y * 255), 0, 255),
clamp(int(color.z * 255), 0, 255),
clamp(int(color.w * 255), 0, 255));
sceGuClearColor(*((uint32*)&c));
#else
glClearColor(color.x, color.y, color.z, color.w);
#endif
}
void setViewport(int x, int y, int width, int height) {
@@ -968,17 +1259,38 @@ namespace Core {
renderState |= RS_TARGET;
}
void setBasis(Basis *basis, int count) {
Core::active.basis = basis;
Core::active.basisCount = count;
Core::active.shader->setParam(uBasis, basis[0], count);
}
void setMaterial(float diffuse, float ambient, float specular, float alpha) {
Core::active.material = vec4(diffuse, ambient, specular, alpha);
Core::active.shader->setParam(uMaterial, Core::active.material);
}
void copyTarget(Texture *dst, int xOffset, int yOffset, int x, int y, int width, int height) {
validateRenderState();
dst->bind(sDiffuse);
#ifdef _PSP
#else
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height); // TODO: too bad for iOS devices!
#endif
}
vec4 copyPixel(int x, int y) { // GPU sync!
validateRenderState();
#ifdef _PSP
return vec4(0.0f);
#else
ubyte4 c;
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &c);
return vec4(float(c.x), float(c.y), float(c.z), float(c.w)) * (1.0f / 255.0f);
#endif
}
void beginFrame() {
@@ -1004,9 +1316,45 @@ namespace Core {
Core::stats.stop();
}
void setViewProj(const mat4 &mView, const mat4 &mProj) {
Core::mProj = mProj;
Core::mView = mView;
Core::mViewProj = mProj * mView;
#ifdef FFP
#ifdef _PSP
sceGumMatrixMode(GU_PROJECTION);
sceGumLoadMatrix((ScePspFMatrix4*)&mProj);
sceGumMatrixMode(GU_VIEW);
sceGumLoadMatrix((ScePspFMatrix4*)&mView);
#else
glMatrixMode(GL_PROJECTION);
glLoadMatrixf((float*)&mProj);
#endif
#endif
}
void DIP(int iStart, int iCount) {
validateRenderState();
#ifdef FFP
#ifdef _PSP
mat4 m = mModel;
m.scale(vec3(32767.0f));
sceGumMatrixMode(GU_MODEL);
sceGumLoadMatrix((ScePspFMatrix4*)&m);
#else
mat4 m = mView * mModel;
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf((GLfloat*)&m);
#endif
#endif
#ifdef _PSP
sceGumDrawArray(GU_TRIANGLES, GU_TEXTURE_16BIT | GU_COLOR_8888 | GU_NORMAL_16BIT | GU_VERTEX_16BIT | GU_INDEX_16BIT | GU_TRANSFORM_3D, iCount, active.iBuffer + iStart, active.vBuffer);
#else
glDrawElements(GL_TRIANGLES, iCount, GL_UNSIGNED_SHORT, (Index*)NULL + iStart);
#endif
stats.dips++;
stats.tris += iCount / 3;
}

View File

@@ -48,6 +48,7 @@ namespace Debug {
}
void begin() {
glDisable(GL_TEXTURE_2D);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf((GLfloat*)&Core::mProj);
glMatrixMode(GL_MODELVIEW);
@@ -64,7 +65,7 @@ namespace Debug {
}
void end() {
//
glEnable(GL_TEXTURE_2D);
}
namespace Draw {
@@ -198,9 +199,9 @@ namespace Debug {
void text(const vec3 &pos, const vec4 &color, const char *str) {
vec4 p = Core::mViewProj * vec4(pos, 1);
if (p.w > 0) {
p.xyz = p.xyz * (1.0f / p.w);
p.xyz() = p.xyz() * (1.0f / p.w);
p.y = -p.y;
p.xyz = (p.xyz * 0.5f + vec3(0.5f)) * vec3(float(Core::width), float(Core::height), 1.0f);
p.xyz() = (p.xyz() * 0.5f + vec3(0.5f)) * vec3(float(Core::width), float(Core::height), 1.0f);
text(vec2(p.x, p.y), color, str);
}
}
@@ -210,7 +211,7 @@ namespace Debug {
#define case_name(a,b) case a::b : return #b
const char *getTriggerType(const TR::Level &level, const TR::Level::Trigger &trigger) {
const char *getTriggerType(const TR::Level &level, const TR::Level::Trigger::Type &trigger) {
switch (trigger) {
case_name(TR::Level::Trigger, ACTIVATE );
case_name(TR::Level::Trigger, PAD );
@@ -225,7 +226,7 @@ namespace Debug {
return "UNKNOWN";
}
const char *getTriggerAction(const TR::Level &level, const TR::Action &action) {
const char *getTriggerAction(const TR::Level &level, uint16 action) {
switch (action) {
case_name(TR::Action, ACTIVATE );
case_name(TR::Action, CAMERA_SWITCH );
@@ -269,14 +270,30 @@ namespace Debug {
vec3 rf[4], rc[4], f[4], c[4];
float offsets[4][2] = { { 1, 1 }, { 1023, 1 }, { 1023, 1023 }, { 1, 1023 } };
int offsets[4][2] = { { 1, 1 }, { 1023, 1 }, { 1023, 1023 }, { 1, 1023 } };
for (int i = 0; i < 4; i++) {
game->getLara()->getFloorInfo(roomIndex, vec3(float(x + offsets[i][0]), float(y), float(z + offsets[i][1])), info);
rf[i] = vec3( x + offsets[i][0], info.roomFloor - 4, z + offsets[i][1] );
rc[i] = vec3( x + offsets[i][0], info.roomCeiling + 4, z + offsets[i][1] );
f[i] = vec3( x + offsets[i][0], info.floor - 4, z + offsets[i][1] );
c[i] = vec3( x + offsets[i][0], info.ceiling + 4, z + offsets[i][1] );
rf[i] = vec3( float(x + offsets[i][0]), info.roomFloor - 4, float(z + offsets[i][1]) );
rc[i] = vec3( float(x + offsets[i][0]), info.roomCeiling + 4, float(z + offsets[i][1]) );
f[i] = vec3( float(x + offsets[i][0]), info.floor - 4, float(z + offsets[i][1]) );
c[i] = vec3( float(x + offsets[i][0]), info.ceiling + 4, float(z + offsets[i][1]) );
/*
int px = x + offsets[i][0];
int py = y;
int pz = z + offsets[i][1];
int dx, dz;
int16 ridx = roomIndex;
TR::Room::Sector *sector = game->getLevel()->getSectorNext(ridx, px, py, pz);
int floor = game->getLevel()->getFloor(sector, px, py, pz);
int ceiling = game->getLevel()->getCeiling(sector, px, py, pz);
f[i] = vec3( px, floor - 4, pz );
c[i] = vec3( px, ceiling + 4, pz );
*/
if (info.roomBelow == TR::NO_ROOM) rf[i].y = f[i].y;
if (info.roomAbove == TR::NO_ROOM) rc[i].y = c[i].y;
}
@@ -531,7 +548,7 @@ namespace Debug {
Debug::Draw::sphere(p, float(l.radius), color);
}
vec4 color = vec4(lara->mainLightColor.xyz, 1.0f);
vec4 color = vec4(lara->mainLightColor.xyz(), 1.0f);
Debug::Draw::point(lara->mainLightPos, color);
Debug::Draw::sphere(lara->mainLightPos, lara->mainLightColor.w, color);
}

View File

@@ -590,7 +590,7 @@ struct Wolf : Enemy {
case STATE_ATTACK :
case STATE_BITE :
if (nextState == STATE_NONE && targetInView && (collide(target) & HIT_MASK)) {
bite(animation.getJoints(getMatrix(), jointHead, true).pos, state == STATE_ATTACK ? 50.0f : 100.0f);
bite(getJoint(jointHead).pos, state == STATE_ATTACK ? 50.0f : 100.0f);
nextState = state == STATE_ATTACK ? STATE_RUN : STATE_GROWL;
}
return state == STATE_ATTACK ? STATE_RUN : state;
@@ -751,7 +751,7 @@ struct Bear : Enemy {
case STATE_BITE :
case STATE_ATTACK :
if (nextState == STATE_NONE && (collide(target) & HIT_MASK)) {
bite(animation.getJoints(getMatrix(), jointHead, true).pos, state == STATE_BITE ? 200.0f : 400.0f);
bite(getJoint(jointHead).pos, state == STATE_BITE ? 200.0f : 400.0f);
nextState = state == STATE_BITE ? STATE_STOP : STATE_HOWL;
}
break;
@@ -832,7 +832,7 @@ struct Bat : Enemy {
mood = MOOD_SLEEP;
return STATE_FLY;
} else
bite(animation.getJoints(getMatrix(), jointHead, true).pos, 2);
bite(getJoint(jointHead).pos, 2);
break;
case STATE_FLY :
if (collide(target)) {
@@ -1071,7 +1071,7 @@ struct Raptor : Enemy {
case STATE_ATTACK_2 :
case STATE_BITE :
if (nextState == STATE_NONE && targetInView && (mask & HIT_MASK)) {
bite(animation.getJoints(getMatrix(), jointHead, true).pos, 100);
bite(getJoint(jointHead).pos, 100);
nextState = state == STATE_ATTACK_2 ? STATE_RUN : STATE_STOP;
}
break;

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,7 @@ struct Frustum {
planes[3] = vec4(m.e30 + m.e10, m.e31 + m.e11, m.e32 + m.e12, m.e33 + m.e13); // bottom
planes[4] = vec4(m.e30 + m.e00, m.e31 + m.e01, m.e32 + m.e02, m.e33 + m.e03); // left
for (int i = 0; i < count; i++)
planes[i] *= 1.0f / planes[i].xyz.length();
planes[i] *= 1.0f / planes[i].xyz().length();
}
// AABB visibility check
@@ -27,7 +27,7 @@ struct Frustum {
if (count < 4) return false;
for (int i = start; i < start + count; i++) {
const vec3 &n = planes[i].xyz;
const vec3 &n = planes[i].xyz();
const float d = -planes[i].w;
if (n.dot(max) < d &&
@@ -50,9 +50,9 @@ struct Frustum {
mat4 m = matrix.inverse();
for (int i = 0; i < count; i++) {
vec4 &p = planes[i];
vec4 o = m * vec4(p.xyz * (-p.w), 1.0f);
vec4 n = m * vec4(p.xyz, 0.0f);
planes[start + i] = vec4(n.xyz, -n.xyz.dot(o.xyz));
vec4 o = m * vec4(p.xyz() * (-p.w), 1.0f);
vec4 n = m * vec4(p.xyz(), 0.0f);
planes[start + i] = vec4(n.xyz(), -n.xyz().dot(o.xyz()));
}
bool visible = isVisible(min, max);
start = 0;
@@ -64,7 +64,7 @@ struct Frustum {
if (count < 4) return false;
for (int i = 0; i < count; i++)
if (planes[i].xyz.dot(center) + planes[i].w < -radius)
if (planes[i].xyz().dot(center) + planes[i].w < -radius)
return false;
return true;
}

View File

@@ -38,7 +38,6 @@ namespace Game {
nextLevel = NULL;
Core::init();
shaderCache = new ShaderCache();
UI::init(level);
@@ -49,21 +48,19 @@ namespace Game {
startLevel(lvl);
}
void init(char *lvlName = NULL, char *sndName = NULL) {
void init(const char *lvlName = NULL) {
char fileName[255];
TR::Version version = TR::getGameVersion();
if (!lvlName && version != TR::VER_UNKNOWN) {
lvlName = fileName;
TR::getGameLevelFile(lvlName, version, TR::getTitleId(version));
}
if (!lvlName) {
lvlName = fileName;
strcpy(lvlName, "level/1/TITLE.PSX");
}
if (version != TR::VER_UNKNOWN)
TR::getGameLevelFile(fileName, version, TR::getTitleId(version));
else
strcpy(fileName, "level/1/TITLE.PSX");
} else
strcpy(fileName, lvlName);
init(new Stream(lvlName));
init(new Stream(fileName));
}
void deinit() {
@@ -152,4 +149,4 @@ namespace Game {
}
}
#endif
#endif

View File

@@ -13,7 +13,7 @@ namespace TR {
NO_TRACK = 0xFF,
};
enum Version : uint32 {
enum Version {
VER_UNKNOWN = 0,
VER_PC = 256,
@@ -38,9 +38,11 @@ namespace TR {
VER_TR3_PC = VER_TR3 | VER_PC,
VER_TR3_PSX = VER_TR3 | VER_PSX,
VER_MAX = 0xFFFFFFFF,
};
enum LevelID : uint32 {
enum LevelID {
LVL_CUSTOM,
// TR1
LVL_TR1_TITLE,
@@ -188,7 +190,7 @@ namespace TR {
TRACK_TR3_CUT_12 = 66,
};
struct {
struct LevelInfo {
const char *name;
const char *title;
int ambientTrack;

View File

@@ -9,14 +9,14 @@ namespace Input {
bool down[ikMAX];
bool state[cMAX];
struct {
struct Mouse {
vec2 pos;
struct {
vec2 L, R, M;
} start;
} mouse;
struct {
struct Joystick {
vec2 L, R;
float LT, RT;
int POV;
@@ -28,7 +28,7 @@ namespace Input {
vec2 pos;
} touch[6];
struct {
struct HMD {
Basis pivot;
Basis basis;
bool ready;

View File

@@ -7,7 +7,12 @@
#define INVENTORY_MAX_ITEMS 32
#define INVENTORY_MAX_RADIUS 688.0f
#define INVENTORY_BG_SIZE 512
#ifdef _PSP
#define INVENTORY_BG_SIZE 256
#else
#define INVENTORY_BG_SIZE 512
#endif
#define INVENTORY_HEIGHT 2048.0f
#define TITLE_LOADING 64.0f
@@ -48,49 +53,52 @@ struct Inventory {
StringID str;
Page page;
int model;
Desc() {}
Desc(StringID str, Page page, int model) : str(str), page(page), model(model) {}
} desc;
Item() : anim(NULL) {}
Item(TR::Level *level, TR::Entity::Type type, int count = 1) : type(type), count(count), angle(0.0f), value(0) {
switch (type) {
case TR::Entity::INV_PASSPORT : desc = { STR_GAME, PAGE_OPTION, level->extra.inv.passport }; break;
case TR::Entity::INV_PASSPORT_CLOSED : desc = { STR_GAME, PAGE_OPTION, level->extra.inv.passport_closed }; break;
case TR::Entity::INV_MAP : desc = { STR_MAP, PAGE_INVENTORY, level->extra.inv.map }; break;
case TR::Entity::INV_COMPASS : desc = { STR_COMPASS, PAGE_INVENTORY, level->extra.inv.compass }; break;
case TR::Entity::INV_STOPWATCH : desc = { STR_STOPWATCH, PAGE_INVENTORY, level->extra.inv.stopwatch }; break;
case TR::Entity::INV_HOME : desc = { STR_HOME, PAGE_OPTION, level->extra.inv.home }; break;
case TR::Entity::INV_DETAIL : desc = { STR_DETAIL, PAGE_OPTION, level->extra.inv.detail }; break;
case TR::Entity::INV_SOUND : desc = { STR_SOUND, PAGE_OPTION, level->extra.inv.sound }; break;
case TR::Entity::INV_CONTROLS : desc = { STR_CONTROLS, PAGE_OPTION, level->extra.inv.controls }; break;
case TR::Entity::INV_GAMMA : desc = { STR_GAMMA, PAGE_OPTION, level->extra.inv.gamma }; break;
case TR::Entity::INV_PASSPORT : desc = Desc( STR_GAME, PAGE_OPTION, level->extra.inv.passport ); break;
case TR::Entity::INV_PASSPORT_CLOSED : desc = Desc( STR_GAME, PAGE_OPTION, level->extra.inv.passport_closed ); break;
case TR::Entity::INV_MAP : desc = Desc( STR_MAP, PAGE_INVENTORY, level->extra.inv.map ); break;
case TR::Entity::INV_COMPASS : desc = Desc( STR_COMPASS, PAGE_INVENTORY, level->extra.inv.compass ); break;
case TR::Entity::INV_STOPWATCH : desc = Desc( STR_STOPWATCH, PAGE_INVENTORY, level->extra.inv.stopwatch ); break;
case TR::Entity::INV_HOME : desc = Desc( STR_HOME, PAGE_OPTION, level->extra.inv.home ); break;
case TR::Entity::INV_DETAIL : desc = Desc( STR_DETAIL, PAGE_OPTION, level->extra.inv.detail ); break;
case TR::Entity::INV_SOUND : desc = Desc( STR_SOUND, PAGE_OPTION, level->extra.inv.sound ); break;
case TR::Entity::INV_CONTROLS : desc = Desc( STR_CONTROLS, PAGE_OPTION, level->extra.inv.controls ); break;
case TR::Entity::INV_GAMMA : desc = Desc( STR_GAMMA, PAGE_OPTION, level->extra.inv.gamma ); break;
case TR::Entity::INV_PISTOLS : desc = { STR_PISTOLS, PAGE_INVENTORY, level->extra.inv.weapon[0] }; break;
case TR::Entity::INV_SHOTGUN : desc = { STR_SHOTGUN, PAGE_INVENTORY, level->extra.inv.weapon[1] }; break;
case TR::Entity::INV_MAGNUMS : desc = { STR_MAGNUMS, PAGE_INVENTORY, level->extra.inv.weapon[2] }; break;
case TR::Entity::INV_UZIS : desc = { STR_UZIS, PAGE_INVENTORY, level->extra.inv.weapon[3] }; break;
case TR::Entity::INV_PISTOLS : desc = Desc( STR_PISTOLS, PAGE_INVENTORY, level->extra.inv.weapon[0] ); break;
case TR::Entity::INV_SHOTGUN : desc = Desc( STR_SHOTGUN, PAGE_INVENTORY, level->extra.inv.weapon[1] ); break;
case TR::Entity::INV_MAGNUMS : desc = Desc( STR_MAGNUMS, PAGE_INVENTORY, level->extra.inv.weapon[2] ); break;
case TR::Entity::INV_UZIS : desc = Desc( STR_UZIS, PAGE_INVENTORY, level->extra.inv.weapon[3] ); break;
case TR::Entity::INV_AMMO_PISTOLS : desc = { STR_AMMO_PISTOLS, PAGE_INVENTORY, level->extra.inv.ammo[0] }; break;
case TR::Entity::INV_AMMO_SHOTGUN : desc = { STR_AMMO_SHOTGUN, PAGE_INVENTORY, level->extra.inv.ammo[1] }; break;
case TR::Entity::INV_AMMO_MAGNUMS : desc = { STR_AMMO_MAGNUMS, PAGE_INVENTORY, level->extra.inv.ammo[2] }; break;
case TR::Entity::INV_AMMO_UZIS : desc = { STR_AMMO_UZIS, PAGE_INVENTORY, level->extra.inv.ammo[3] }; break;
case TR::Entity::INV_AMMO_PISTOLS : desc = Desc( STR_AMMO_PISTOLS, PAGE_INVENTORY, level->extra.inv.ammo[0] ); break;
case TR::Entity::INV_AMMO_SHOTGUN : desc = Desc( STR_AMMO_SHOTGUN, PAGE_INVENTORY, level->extra.inv.ammo[1] ); break;
case TR::Entity::INV_AMMO_MAGNUMS : desc = Desc( STR_AMMO_MAGNUMS, PAGE_INVENTORY, level->extra.inv.ammo[2] ); break;
case TR::Entity::INV_AMMO_UZIS : desc = Desc( STR_AMMO_UZIS, PAGE_INVENTORY, level->extra.inv.ammo[3] ); break;
case TR::Entity::INV_MEDIKIT_SMALL : desc = { STR_MEDI_SMALL, PAGE_INVENTORY, level->extra.inv.medikit[0] }; break;
case TR::Entity::INV_MEDIKIT_BIG : desc = { STR_MEDI_BIG, PAGE_INVENTORY, level->extra.inv.medikit[1] }; break;
case TR::Entity::INV_MEDIKIT_SMALL : desc = Desc( STR_MEDI_SMALL, PAGE_INVENTORY, level->extra.inv.medikit[0] ); break;
case TR::Entity::INV_MEDIKIT_BIG : desc = Desc( STR_MEDI_BIG, PAGE_INVENTORY, level->extra.inv.medikit[1] ); break;
case TR::Entity::INV_PUZZLE_1 : desc = { STR_PUZZLE, PAGE_ITEMS, level->extra.inv.puzzle[0] }; break;
case TR::Entity::INV_PUZZLE_2 : desc = { STR_PUZZLE, PAGE_ITEMS, level->extra.inv.puzzle[1] }; break;
case TR::Entity::INV_PUZZLE_3 : desc = { STR_PUZZLE, PAGE_ITEMS, level->extra.inv.puzzle[2] }; break;
case TR::Entity::INV_PUZZLE_4 : desc = { STR_PUZZLE, PAGE_ITEMS, level->extra.inv.puzzle[3] }; break;
case TR::Entity::INV_PUZZLE_1 : desc = Desc( STR_PUZZLE, PAGE_ITEMS, level->extra.inv.puzzle[0] ); break;
case TR::Entity::INV_PUZZLE_2 : desc = Desc( STR_PUZZLE, PAGE_ITEMS, level->extra.inv.puzzle[1] ); break;
case TR::Entity::INV_PUZZLE_3 : desc = Desc( STR_PUZZLE, PAGE_ITEMS, level->extra.inv.puzzle[2] ); break;
case TR::Entity::INV_PUZZLE_4 : desc = Desc( STR_PUZZLE, PAGE_ITEMS, level->extra.inv.puzzle[3] ); break;
case TR::Entity::INV_KEY_1 : desc = { STR_KEY, PAGE_ITEMS, level->extra.inv.key[0] }; break;
case TR::Entity::INV_KEY_2 : desc = { STR_KEY, PAGE_ITEMS, level->extra.inv.key[1] }; break;
case TR::Entity::INV_KEY_3 : desc = { STR_KEY, PAGE_ITEMS, level->extra.inv.key[2] }; break;
case TR::Entity::INV_KEY_4 : desc = { STR_KEY, PAGE_ITEMS, level->extra.inv.key[3] }; break;
case TR::Entity::INV_KEY_1 : desc = Desc( STR_KEY, PAGE_ITEMS, level->extra.inv.key[0] ); break;
case TR::Entity::INV_KEY_2 : desc = Desc( STR_KEY, PAGE_ITEMS, level->extra.inv.key[1] ); break;
case TR::Entity::INV_KEY_3 : desc = Desc( STR_KEY, PAGE_ITEMS, level->extra.inv.key[2] ); break;
case TR::Entity::INV_KEY_4 : desc = Desc( STR_KEY, PAGE_ITEMS, level->extra.inv.key[3] ); break;
case TR::Entity::INV_LEADBAR : desc = { STR_LEAD_BAR, PAGE_ITEMS, level->extra.inv.leadbar }; break;
case TR::Entity::INV_SCION : desc = { STR_SCION, PAGE_ITEMS, level->extra.inv.scion }; break;
default : desc = { STR_UNKNOWN, PAGE_ITEMS, -1 }; break;
case TR::Entity::INV_LEADBAR : desc = Desc( STR_LEAD_BAR, PAGE_ITEMS, level->extra.inv.leadbar ); break;
case TR::Entity::INV_SCION : desc = Desc( STR_SCION, PAGE_ITEMS, level->extra.inv.scion ); break;
default : desc = Desc( STR_UNKNOWN, PAGE_ITEMS, -1 ); break;
}
if (desc.model > -1 && level->models[desc.model].animation != 0xFFFF) {
@@ -142,9 +150,14 @@ struct Inventory {
TR::Model &m = level->models[desc.model];
Basis joints[MAX_SPHERES];
anim->getJoints(basis, -1, true, joints);
mat4 matrix;
matrix.identity();
matrix.setRot(basis.rot);
matrix.setPos(basis.pos);
Core::active.shader->setParam(uBasis, joints[0], m.mCount);
anim->getJoints(matrix, -1, true, joints);
Core::setBasis(joints, m.mCount);
Core::setBlending(bmNone);
mesh->transparent = 0;
@@ -775,6 +788,16 @@ struct Inventory {
Core::setDepthTest(false);
Core::setBlending(bmNone);
#ifdef FFP
mat4 m;
m.identity();
Core::setViewProj(m, m);
Core::mModel.identity();
#endif
#ifdef _PSP
//
#else
// vertical blur
Core::setTarget(background[1], true);
game->setShader(Core::passFilter, Shader::FILTER_BLUR, false, false);
@@ -792,9 +815,10 @@ struct Inventory {
// grayscale
Core::setTarget(background[1], true);
game->setShader(Core::passFilter, Shader::FILTER_GRAYSCALE, false, false);
Core::active.shader->setParam(uParam, vec4(1, 0, 0, 0));;
Core::active.shader->setParam(uParam, vec4(1, 0, 0, 0));
background[2]->bind(sDiffuse);
game->getMesh()->renderQuad();
#endif
Core::setTarget(NULL, true);
@@ -1050,6 +1074,14 @@ struct Inventory {
Core::setDepthTest(false);
if (background[0]) {
#ifdef FFP
mat4 m;
m.identity();
Core::setViewProj(m, m);
Core::mModel.identity();
// Core::mModel.scale(vec3(0.9f));
#endif
background[0]->bind(sDiffuse); // orignal image
if (background[1]) {
game->setShader(Core::passFilter, Shader::FILTER_MIXER, false, false);
@@ -1091,14 +1123,15 @@ struct Inventory {
Core::mView.identity();
Core::mView.translate(vec3(-Core::eye * 8.0f, 0, -1286)); // y = -96 in title
Core::mView.up *= -1.0f;
Core::mView.dir *= -1.0f;
Core::mView.up() *= -1.0f;
Core::mView.dir() *= -1.0f;
Core::mViewInv = Core::mView.inverse();
float aspect = float(Core::width) / float(Core::height);
Core::mProj = mat4(70.0f, aspect, 32.0f, 2048.0f);
Core::mViewProj = Core::mProj * Core::mView;
Core::setViewProj(Core::mView, Core::mProj);
Core::viewPos = Core::mViewInv.getPos();
Core::whiteTex->bind(sShadow);

View File

@@ -179,7 +179,7 @@ struct Lara : Character {
STATE_WATER_OUT,
STATE_MAX };
enum : int {
enum {
BODY_HIP = 0x0001,
BODY_LEG_L1 = 0x0002,
BODY_LEG_L2 = 0x0004,
@@ -209,22 +209,24 @@ struct Lara : Character {
struct Weapon {
enum Type { EMPTY = -1, PISTOLS, SHOTGUN, MAGNUMS, UZIS, MAX };
enum State { IS_HIDDEN, IS_ARMED, IS_FIRING };
enum Anim { NONE, PREPARE, UNHOLSTER, HOLSTER, HOLD, AIM, FIRE };
struct Anim {
enum Type { NONE, PREPARE, UNHOLSTER, HOLSTER, HOLD, AIM, FIRE };
};
};
Weapon::Type wpnCurrent;
Weapon::Type wpnNext;
Weapon::State wpnState;
int *wpnAmmo;
vec3 chestOffset;
struct Arm {
Controller *tracking; // tracking target (main target)
Controller *target; // target for shooting
float shotTimer;
quat rot, rotAbs;
Weapon::Anim anim;
Animation animation;
Weapon::Anim::Type anim;
Animation animation;
Arm() : tracking(NULL), target(NULL) {}
} arms[2];
@@ -290,7 +292,7 @@ struct Lara : Character {
}
Basis getBasis() {
return lara->animation.getJoints(lara->getMatrix(), 14, true);
return lara->getJoint(lara->jointHead);
}
vec3 getPos() {
@@ -338,13 +340,15 @@ struct Lara : Character {
#define BRAID_RADIUS 16.0f
lara->updateJoints();
for (int i = 0; i < model->mCount; i++) {
if (!(BODY_BRAID_MASK & (1 << i))) continue;
int offset = level->meshOffsets[model->mStart + i];
TR::Mesh *mesh = (TR::Mesh*)&level->meshes[offset];
vec3 center = lara->animation.getJoints(lara->getMatrix(), i, true) * mesh->center;
vec3 center = lara->joints[i] * mesh->center;
float radiusSq = mesh->radius + BRAID_RADIUS;
radiusSq *= radiusSq;
@@ -397,10 +401,10 @@ struct Lara : Character {
vec3 u = d.cross(r).normal();
mat4 m;
m.up = vec4(u, 0.0f);
m.dir = vec4(d, 0.0f);
m.right = vec4(r, 0.0f);
m.offset = vec4(0.0f, 0.0f, 0.0f, 1.0f);
m.up() = vec4(u, 0.0f);
m.dir() = vec4(d, 0.0f);
m.right() = vec4(r, 0.0f);
m.offset() = vec4(0.0f, 0.0f, 0.0f, 1.0f);
basis[i].identity();
basis[i].translate(joints[i].pos);
@@ -409,13 +413,13 @@ struct Lara : Character {
}
void render(MeshBuilder *mesh) {
Core::active.shader->setParam(uBasis, basis[0], jointsCount - 1);
Core::setBasis(basis, jointsCount - 1);
mesh->renderModel(lara->level->extra.braid);
}
} *braid;
Lara(IGame *game, int entity) : Character(game, entity, LARA_MAX_HEALTH), dozy(false), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos), braid(NULL) {
Lara(IGame *game, int entity) : Character(game, entity, LARA_MAX_HEALTH), dozy(false), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), braid(NULL) {
if (level->extra.laraSkin > -1)
level->entities[entity].modelIndex = level->extra.laraSkin + 1;
@@ -516,8 +520,6 @@ struct Lara : Character {
} else
animation.setAnim(ANIM_STAND);
}
chestOffset = animation.getJoints(getMatrix(), jointChest).pos;
}
virtual ~Lara() {
@@ -621,11 +623,11 @@ struct Lara : Character {
TR::Entity::Type getCurrentWeaponInv() {
switch (wpnCurrent) {
case Weapon::Type::PISTOLS : return TR::Entity::PISTOLS;
case Weapon::Type::SHOTGUN : return TR::Entity::SHOTGUN;
case Weapon::Type::MAGNUMS : return TR::Entity::MAGNUMS;
case Weapon::Type::UZIS : return TR::Entity::UZIS;
default : return TR::Entity::LARA;
case Weapon::PISTOLS : return TR::Entity::PISTOLS;
case Weapon::SHOTGUN : return TR::Entity::SHOTGUN;
case Weapon::MAGNUMS : return TR::Entity::MAGNUMS;
case Weapon::UZIS : return TR::Entity::UZIS;
default : return TR::Entity::LARA;
}
}
@@ -643,7 +645,7 @@ struct Lara : Character {
wpnSetAnim(arms[1], Weapon::IS_HIDDEN, Weapon::Anim::NONE, 0.0f, 0.0f);
}
void wpnSetAnim(Arm &arm, Weapon::State wState, Weapon::Anim wAnim, float wAnimTime, float wAnimDir, bool playing = true) {
void wpnSetAnim(Arm &arm, Weapon::State wState, Weapon::Anim::Type wAnim, float wAnimTime, float wAnimDir, bool playing = true) {
arm.animation.setAnim(wpnGetAnimIndex(wAnim), 0, wAnim == Weapon::Anim::FIRE);
arm.animation.dir = playing ? wAnimDir : 0.0f;
@@ -698,8 +700,8 @@ struct Lara : Character {
default : ;
}
if (wpnState == Weapon::IS_HIDDEN && wState == Weapon::IS_ARMED) game->playSound(TR::SND_UNHOLSTER, pos, Sound::Flags::PAN);
if (wpnState == Weapon::IS_ARMED && wState == Weapon::IS_HIDDEN) game->playSound(TR::SND_HOLSTER, pos, Sound::Flags::PAN);
if (wpnState == Weapon::IS_HIDDEN && wState == Weapon::IS_ARMED) game->playSound(TR::SND_UNHOLSTER, pos, Sound::PAN);
if (wpnState == Weapon::IS_ARMED && wState == Weapon::IS_HIDDEN) game->playSound(TR::SND_HOLSTER, pos, Sound::PAN);
// swap layers
// 0 - body (full)
@@ -823,7 +825,7 @@ struct Lara : Character {
wpnHide();
}
int wpnGetAnimIndex(Weapon::Anim wAnim) {
int wpnGetAnimIndex(Weapon::Anim::Type wAnim) {
if (wpnCurrent == Weapon::SHOTGUN) {
switch (wAnim) {
case Weapon::Anim::PREPARE : ASSERT(false); break; // rifle has no prepare animation
@@ -874,7 +876,7 @@ struct Lara : Character {
// shotgun reload sound
if (wpnCurrent == Weapon::SHOTGUN) {
if (anim.frameIndex == 10)
game->playSound(TR::SND_SHOTGUN_RELOAD, pos, Sound::Flags::PAN);
game->playSound(TR::SND_SHOTGUN_RELOAD, pos, Sound::PAN);
}
}
}
@@ -916,7 +918,7 @@ struct Lara : Character {
int joint = wpnCurrent == Weapon::SHOTGUN ? 8 : (i ? 11 : 8);
vec3 p = animation.getJoints(getMatrix(), joint, false).pos;
vec3 p = getJoint(joint).pos;
vec3 d = arm->rotAbs * vec3(0, 0, 1);
vec3 t = p + d * (24.0f * 1024.0f) + ((vec3(randf(), randf(), randf()) * 2.0f) - vec3(1.0f)) * 1024.0f;
@@ -939,13 +941,13 @@ struct Lara : Character {
}
}
Core::lightPos[1 + armIndex] = animation.getJoints(getMatrix(), armIndex == 0 ? 10 : 13, false).pos;
Core::lightPos[1 + armIndex] = getJoint(armIndex == 0 ? 10 : 13).pos;
Core::lightColor[1 + armIndex] = FLASH_LIGHT_COLOR;
}
if (shots) {
game->playSound(wpnGetSound(), pos, Sound::Flags::PAN);
game->playSound(TR::SND_RICOCHET, nearPos, Sound::Flags::PAN);
game->playSound(wpnGetSound(), pos, Sound::PAN);
game->playSound(TR::SND_RICOCHET, nearPos, Sound::PAN);
if (wpnAmmo && *wpnAmmo != UNLIMITED_AMMO && wpnCurrent == Weapon::SHOTGUN)
*wpnAmmo -= 1;
@@ -1122,6 +1124,7 @@ struct Lara : Character {
}
animation.overrideMask = overrideMask;
jointsFrame = -1;
}
virtual void lookAt(Controller *target) {
@@ -1164,7 +1167,7 @@ struct Lara : Character {
Arm &arm = arms[i];
int j = joints[i];
if (!aim(arm.target, j, ranges[i], rot, &arm.rotAbs)) {
if (!aim(arm.target, j, ranges[i], rot, &arm.rotAbs)) {
arm.target = arms[i^1].target;
if (!aim(arm.target, j, ranges[i], rot, &arm.rotAbs)) {
rot = quat(0, 0, 0, 1);
@@ -1182,6 +1185,7 @@ struct Lara : Character {
arm.rot = arm.rot.slerp(rot, speed);
animation.overrides[j] = animation.overrides[j].slerp(arm.rot * animation.overrides[j], t);
jointsFrame = -1;
}
}
@@ -1372,8 +1376,8 @@ struct Lara : Character {
void doBubbles() {
int count = rand() % 3;
if (!count) return;
game->playSound(TR::SND_BUBBLE, pos, Sound::Flags::PAN);
vec3 head = animation.getJoints(getMatrix(), 14, true) * vec3(0.0f, 0.0f, 50.0f);
game->playSound(TR::SND_BUBBLE, pos, Sound::PAN);
vec3 head = getJoint(jointHead) * vec3(0.0f, 0.0f, 50.0f);
for (int i = 0; i < count; i++)
game->addEntity(TR::Entity::BUBBLE, getRoomIndex(), head, 0);
}
@@ -1436,7 +1440,7 @@ struct Lara : Character {
void bakeEnvironment() {
flags.invisible = true;
if (!environment)
environment = new Texture(256, 256, Texture::RGBA, true, NULL, true, true);
environment = new Texture(256, 256, Texture::RGBA, Texture::CUBEMAP | Texture::MIPMAPS);
Core::beginFrame();
game->renderEnvironment(getRoomIndex(), pos - vec3(0.0f, 384.0f, 0.0f), &environment, 0, Core::passCompose);
environment->generateMipMap();
@@ -1733,11 +1737,11 @@ struct Lara : Character {
if (!limit->alignHoriz)
fx = (m.transpose() * vec4(pos - controller->pos, 0.0f)).x;
vec3 targetPos = controller->pos + (m * vec4(fx, limit->dy, limit->dz, 0.0f)).xyz;
vec3 targetPos = controller->pos + (m * vec4(fx, limit->dy, limit->dz, 0.0f)).xyz();
vec3 deltaAbs = pos - targetPos;
vec3 deltaRel = (m.transpose() * vec4(pos - controller->pos, 0.0f)).xyz; // inverse transform
vec3 deltaRel = (m.transpose() * vec4(pos - controller->pos, 0.0f)).xyz(); // inverse transform
// set item orientation to hack limits check
if (limit->box.contains(deltaRel)) {
@@ -1883,7 +1887,7 @@ struct Lara : Character {
}
bool needFlip = false;
TR::Effect effect = TR::Effect::NONE;
TR::Effect::Type effect = TR::Effect::NONE;
int cameraIndex = -1;
Controller *cameraTarget = NULL;
@@ -2001,7 +2005,7 @@ struct Lara : Character {
break;
}
case TR::Action::EFFECT :
effect = TR::Effect(cmd.args);
effect = TR::Effect::Type(cmd.args);
break;
case TR::Action::SECRET :
if (!(level->state.progress.secrets & (1 << cmd.args))) {
@@ -2436,10 +2440,10 @@ struct Lara : Character {
if (state == STATE_SURF_TREAD) {
if (animation.isFrameActive(0))
game->waterDrop(animation.getJoints(getMatrix(), jointHead).pos, 96.0f, 0.03f);
game->waterDrop(getJoint(jointHead).pos, 96.0f, 0.03f);
} else {
if (animation.frameIndex % 4 == 0)
game->waterDrop(animation.getJoints(getMatrix(), jointHead).pos, 96.0f, 0.02f);
game->waterDrop(getJoint(jointHead).pos, 96.0f, 0.02f);
}
if (input & FORTH) {
@@ -2635,7 +2639,7 @@ struct Lara : Character {
arms[i].shotTimer += Core::deltaTime;
float intensity = clamp((0.1f - arms[i].shotTimer) * 20.0f, EPS, 1.0f);
Core::lightColor[1 + i] = FLASH_LIGHT_COLOR * vec4(intensity, intensity, intensity, 1.0f / sqrtf(intensity));
Core::lightPos[1 + i] = animation.getJoints(getMatrix(), i == 0 ? 10 : 13, false).pos;
Core::lightPos[1 + i] = getJoint(i == 0 ? 10 : 13).pos;
} else {
Core::lightColor[1 + i] = vec4(0, 0, 0, 1);
}
@@ -2805,7 +2809,7 @@ struct Lara : Character {
}
virtual vec3 getPos() {
return level->isCutsceneLevel() ? chestOffset : pos;
return level->isCutsceneLevel() ? getViewPoint() : pos;
}
bool checkCollisions() {
@@ -3100,29 +3104,27 @@ struct Lara : Character {
float alpha = min(1.0f, (0.1f - time) * 20.0f);
float lum = 3.0f;
Basis b(basis);
b.w = 1.0f;
b.rotate(quat(vec3(1, 0, 0), -PI * 0.5f));
b.translate(offset);
if (level->version & (TR::VER_TR2 | TR::VER_TR3))
lum = alpha;
Core::active.shader->setParam(uMaterial, vec4(lum, 0.0f, 0.0f, alpha));
Core::active.shader->setParam(uBasis, b);
Core::setBasis(&b, 1);
mesh->renderModel(level->extra.muzzleFlash);
}
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) { // TODO TR3 render in additive pass
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
uint32 visMask = visibleMask;
if (Core::pass != Core::passShadow && game->getCamera()->firstPerson) // hide head from first person view
if (Core::pass != Core::passShadow && game->getCamera()->firstPerson) // hide head in first person view
visibleMask &= ~BODY_HEAD;
Controller::render(frustum, mesh, type, caustics);
visibleMask = visMask;
chestOffset = animation.getJoints(getMatrix(), jointChest).pos; // TODO: move to update func
if (braid)
braid->render(mesh);
if (wpnCurrent != Weapon::SHOTGUN && Core::pass != Core::passShadow && (arms[0].shotTimer < MUZZLE_FLASH_TIME || arms[1].shotTimer < MUZZLE_FLASH_TIME)) {
mat4 matrix = getMatrix();
game->setShader(Core::pass, Shader::FLASH, false, true);
int meshTransp = mesh->transparent;
@@ -3136,8 +3138,8 @@ struct Lara : Character {
zOffset = 150;
}
renderMuzzleFlash(mesh, animation.getJoints(matrix, 10, true), vec3(-10, -50, zOffset), arms[0].shotTimer);
renderMuzzleFlash(mesh, animation.getJoints(matrix, 13, true), vec3( 10, -50, zOffset), arms[1].shotTimer);
renderMuzzleFlash(mesh, joints[10], vec3(-10, -50, zOffset), arms[0].shotTimer);
renderMuzzleFlash(mesh, joints[13], vec3( 10, -50, zOffset), arms[1].shotTimer);
mesh->transparent = meshTransp;
switch (mesh->transparent) {

View File

@@ -34,7 +34,7 @@ struct Level : IGame {
float waterHeight;
float clipSign;
float clipHeight;
} *params = (Params*)&Core::params;
} *params;
ZoneCache *zoneCache;
AmbientCache *ambientCache;
@@ -47,7 +47,7 @@ struct Level : IGame {
bool lastTitle;
bool isEnded;
TR::Effect effect;
TR::Effect::Type effect;
float effectTimer;
int effectIdx;
float cutsceneWaitTimer;
@@ -235,7 +235,7 @@ struct Level : IGame {
if (rebuildMesh) {
delete mesh;
mesh = new MeshBuilder(level);
mesh = new MeshBuilder(level, atlas);
}
if (rebuildAmbient) {
@@ -262,6 +262,10 @@ struct Level : IGame {
return mesh;
}
virtual Texture* getAtlas() {
return atlas;
}
virtual ICamera* getCamera() {
return camera;
}
@@ -332,7 +336,7 @@ struct Level : IGame {
}
Core::active.shader->setParam(uParam, Core::params);
Core::active.shader->setParam(uMaterial, vec4(diffuse, ambient, specular, alpha));
Core::setMaterial(diffuse, ambient, specular, alpha);
if (Core::settings.detail.shadows > Core::Settings::MEDIUM)
Core::active.shader->setParam(uContacts, Core::contacts[0], MAX_CONTACTS);
@@ -356,7 +360,7 @@ struct Level : IGame {
for (int i = 0; i < 6; i++) {
setupCubeCamera(pos, i);
Core::pass = pass;
Texture *target = targets[0]->cube ? targets[0] : targets[i * stride];
Texture *target = (targets[0]->opt & Texture::CUBEMAP) ? targets[0] : targets[i * stride];
Core::setTarget(target, true, i);
renderView(roomIndex, false);
Core::invalidateTarget(false, true);
@@ -364,7 +368,7 @@ struct Level : IGame {
Core::pass = tmpPass;
}
virtual void setEffect(Controller *controller, TR::Effect effect) {
virtual void setEffect(Controller *controller, TR::Effect::Type effect) {
this->effect = effect;
this->effectTimer = 0.0f;
this->effectIdx = 0;
@@ -461,6 +465,7 @@ struct Level : IGame {
}
virtual Sound::Sample* playSound(int id, const vec3 &pos = vec3(0.0f), int flags = 0) const {
//return NULL;
if (level.version == TR::VER_TR1_PSX && id == TR::SND_SECRET)
return NULL;
@@ -547,15 +552,18 @@ struct Level : IGame {
//==============================
Level(Stream &stream) : level(stream), inventory(this), lara(NULL), isEnded(false), cutsceneWaitTimer(0.0f) {
#ifdef _PSP
Core::freeEDRAM();
#endif
params = (Params*)&Core::params;
params->time = 0.0f;
#ifdef _DEBUG
Debug::init();
#endif
initTextures();
mesh = new MeshBuilder(level);
initTextures();
mesh = new MeshBuilder(level, atlas);
initOverrides();
for (int i = 0; i < level.entitiesBaseCount; i++) {
@@ -918,15 +926,21 @@ struct Level : IGame {
}
void initTextures() {
if (!level.tilesCount) {
atlas = NULL;
return;
}
ASSERT(level.tilesCount);
#ifndef SPLIT_BY_TILE
#ifdef _PSP
#error atlas packing is not allowed for this platform
#endif
level.initTiles();
int texIdx = (level.version & TR::VER_PSX) ? 256 : 0; // skip palette color for PSX version
// repack texture tiles
Atlas *tiles = new Atlas(level.objectTexturesCount + level.spriteTexturesCount + UI::BAR_MAX, &level, fillCallback);
// add textures
int texIdx = (level.version & TR::VER_PSX) ? 256 : 0; // skip palette color for PSX version
for (int i = texIdx; i < level.objectTexturesCount; i++) {
TR::ObjectTexture &t = level.objectTextures[i];
int16 tx = (t.tile.index % 4) * 256;
@@ -955,7 +969,7 @@ struct Level : IGame {
tiles->add(uv, texIdx++);
}
// add common textures
const short2 bar[UI::BAR_MAX] = { {0, 4}, {0, 4}, {0, 4}, {4, 4}, {0, 0} };
const short2 bar[UI::BAR_MAX] = { short2(0, 4), short2(0, 4), short2(0, 4), short2(4, 4), short2(0, 0) };
for (int i = 0; i < UI::BAR_MAX; i++)
tiles->add(short4(i * 32, 4096, i * 32 + bar[i].x, 4096 + bar[i].y), texIdx++);
@@ -973,6 +987,57 @@ struct Level : IGame {
delete[] level.tiles;
level.tiles = NULL;
#else
cube = NULL;
#ifdef _PSP
atlas = new Texture(level.tiles4, level.tilesCount, level.cluts, level.clutsCount);
#else
level.initTiles();
atlas = new Texture(level.tiles, level.tilesCount);
delete[] level.tiles;
level.tiles = NULL;
#endif
for (int i = 0; i < level.objectTexturesCount; i++) {
TR::ObjectTexture &t = level.objectTextures[i];
t.texCoord[0].x <<= 7;
t.texCoord[0].y <<= 7;
t.texCoord[1].x <<= 7;
t.texCoord[1].y <<= 7;
t.texCoord[2].x <<= 7;
t.texCoord[2].y <<= 7;
t.texCoord[3].x <<= 7;
t.texCoord[3].y <<= 7;
t.texCoord[0].x += 64;
t.texCoord[0].y += 64;
t.texCoord[1].x += 64;
t.texCoord[1].y += 64;
t.texCoord[2].x += 64;
t.texCoord[2].y += 64;
t.texCoord[3].x += 64;
t.texCoord[3].y += 64;
}
for (int i = 0; i < level.spriteTexturesCount; i++) {
TR::SpriteTexture &t = level.spriteTextures[i];
t.texCoord[0].x <<= 7;
t.texCoord[0].y <<= 7;
t.texCoord[1].x <<= 7;
t.texCoord[1].y <<= 7;
/*
t.texCoord[0].x += 16;
t.texCoord[0].y += 16;
t.texCoord[1].x += 16;
t.texCoord[1].y += 16;
*/
}
#endif
}
void initOverrides() {
@@ -1027,7 +1092,7 @@ struct Level : IGame {
void setMainLight(Controller *controller) {
Core::lightPos[0] = controller->mainLightPos;
Core::lightColor[0] = vec4(controller->mainLightColor.xyz, 1.0f / controller->mainLightColor.w);
Core::lightColor[0] = vec4(controller->mainLightColor.xyz(), 1.0f / controller->mainLightColor.w);
}
void renderSky() {
@@ -1051,7 +1116,8 @@ struct Level : IGame {
Core::setDepthTest(false);
setShader(Core::pass, Shader::FLASH, false, false);
Core::active.shader->setParam(uMaterial, vec4(0.5f, 0.0f, 0.0f, 0.0f));
Core::active.shader->setParam(uBasis, b);// anim.getJoints(Basis(quat(0, 0, 0, 1), vec3(0)), 0, false));//Basis(anim.getJointRot(0), vec3(0)));
// anim.getJoints(Basis(quat(0, 0, 0, 1), vec3(0)), 0, false));//Basis(anim.getJointRot(0), vec3(0)));
Core::setBasis(&b, 1);
mesh->transparent = 0;
mesh->renderModel(level.extra.sky);
@@ -1102,6 +1168,8 @@ struct Level : IGame {
Basis basis;
basis.identity();
Core::mModel.identity();
switch (transp) {
case 0 : Core::setBlending(bmNone); break;
case 1 : Core::setBlending(bmAlpha); break;
@@ -1122,7 +1190,7 @@ struct Level : IGame {
int roomIndex = roomsList[i];
MeshBuilder::RoomRange &range = mesh->rooms[roomIndex];
if (!range.geometry[transp].iCount) {
if (!range.geometry[transp].count) {
i += dir;
continue;
}
@@ -1134,7 +1202,9 @@ struct Level : IGame {
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
basis.pos = level.rooms[roomIndex].getOffset();
sh->setParam(uBasis, basis);
Core::setBasis(&basis, 1);
Core::mModel.setPos(basis.pos);
mesh->transparent = transp;
mesh->renderRoomGeometry(roomIndex);
@@ -1147,7 +1217,12 @@ struct Level : IGame {
if (transp == 1) {
Core::setBlending(bmAlpha);
basis.rot = Core::mViewInv.getRot();
#ifdef MERGE_SPRITES
basis.rot = Core::mViewInv.getRot();
#else
basis.rot = quat(0, 0, 0, 1);
#endif
for (int i = 0; i < roomsCount; i++) {
level.rooms[roomsList[i]].flags.visible = true;
@@ -1164,7 +1239,8 @@ struct Level : IGame {
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
basis.pos = level.rooms[roomIndex].getOffset();
sh->setParam(uBasis, basis);
Core::setBasis(&basis, 1);
mesh->renderRoomSprites(roomIndex);
}
}
@@ -1178,9 +1254,9 @@ struct Level : IGame {
bool isModel = entity.modelIndex > 0;
if (isModel) {
if (!mesh->models[entity.modelIndex - 1].geometry[mesh->transparent].iCount) return;
if (!mesh->models[entity.modelIndex - 1].geometry[mesh->transparent].count) return;
} else {
if (mesh->sequences[-(entity.modelIndex + 1)].transp != mesh->transparent) return;
if (mesh->sequences[-(entity.modelIndex + 1)].transp != mesh->transparent) return;
}
Controller *controller = (Controller*)entity.controller;
@@ -1209,7 +1285,7 @@ struct Level : IGame {
vec3 pos = controller->getPos();
if (ambientCache) {
AmbientCache::Cube cube;
if (Core::stats.frame != controller->frameIndex) {
if (Core::stats.frame != controller->jointsFrame) {
ambientCache->getAmbient(roomIndex, pos, cube);
if (cube.status == AmbientCache::Cube::READY)
memcpy(controller->ambient, cube.colors, sizeof(cube.colors)); // store last calculated ambient into controller
@@ -1379,7 +1455,7 @@ struct Level : IGame {
for (int i = 0; i < level.entitiesCount; i++) {
TR::Entity &entity = level.entities[i];
Controller *controller = (Controller*)entity.controller;
if (controller && controller->flags.rendered)
if (controller && controller->flags.rendered && controller->getEntity().castShadow())
controller->renderShadow(mesh);
}
Core::setBlending(bmNone);
@@ -1409,7 +1485,7 @@ struct Level : IGame {
p[i] = Core::mViewProj * vec4(vec3(portal.vertices[i]) + room.getOffset(), 1.0f);
if (p[i].w > 0.0f) {
p[i].xyz *= (1.0f / p[i].w);
p[i].xyz() *= (1.0f / p[i].w);
clipPort.x = min(clipPort.x, p[i].x);
clipPort.y = min(clipPort.y, p[i].y);
@@ -1568,7 +1644,7 @@ struct Level : IGame {
Core::mView = Core::mViewInv.inverse();
Core::mProj = mat4(90, 1.0f, camera->znear, camera->zfar);
Core::mViewProj = Core::mProj * Core::mView;
Core::viewPos = Core::mViewInv.offset.xyz;
Core::viewPos = Core::mViewInv.offset().xyz();
}
void setupLightCamera() {
@@ -1590,7 +1666,7 @@ struct Level : IGame {
Core::eye = 0.0f;
Core::pass = Core::passShadow;
shadow->unbind(sShadow);
bool colorShadow = shadow->format == Texture::Format::RGBA ? true : false;
bool colorShadow = shadow->format == Texture::RGBA ? true : false;
if (colorShadow)
Core::setClearColor(vec4(1.0f));
Core::setTarget(shadow, true);
@@ -1704,9 +1780,9 @@ struct Level : IGame {
// Box bbox = lara->getBoundingBox();
// Debug::Draw::box(bbox.min, bbox.max, vec4(1, 0, 1, 1));
// Core::setBlending(bmAlpha);
// Core::setDepthTest(false);
// Core::validateRenderState();
Core::setBlending(bmAlpha);
Core::setDepthTest(false);
Core::validateRenderState();
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
// Debug::Level::lights(level, lara->getRoomIndex(), lara);
// Debug::Level::sectors(this, lara->getRoomIndex(), (int)lara->pos.y);
@@ -1720,8 +1796,8 @@ struct Level : IGame {
// Debug::Level::path(level, (Enemy*)level.entities[86].controller);
// Debug::Level::debugOverlaps(level, lara->box);
// Debug::Level::debugBoxes(level, lara->dbgBoxes, lara->dbgBoxesCount);
// Core::setDepthTest(true);
// Core::setBlending(bmNone);
Core::setDepthTest(true);
Core::setBlending(bmNone);
/*
static int dbg_ambient = 0;

File diff suppressed because it is too large Load Diff

BIN
src/platform/psp/ICON0.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

23
src/platform/psp/Makefile Normal file
View File

@@ -0,0 +1,23 @@
TARGET = OpenLara
OBJS = main.o
INCDIR = ../../
CFLAGS = -G0 -O3
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
BUILD_PRX = 1
LIBDIR =
LDFLAGS =
LIBS = -lpspgum -lpspgu -lpspaudiolib -lpspaudio -lpsprtc -lpspmath -lm -lstdc++
COPY_DIR = D:/Games/PSP/memstick/PSP/GAME/OL/
EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = OpenLara
PSP_EBOOT_ICON = ICON0.PNG
PSP_EBOOT_PIC1 = PIC1.PNG
PSPSDK = $(shell psp-config --pspsdk-path)
#USE_PSPSDK_LIBC=1
include $(PSPSDK)/lib/build.mak

BIN
src/platform/psp/PIC1.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

165
src/platform/psp/main.cpp Normal file
View File

@@ -0,0 +1,165 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pspkernel.h>
#include <pspdisplay.h>
//#include <pspdebug.h>
#include <pspctrl.h>
#include <psprtc.h>
#include <pspaudiolib.h>
#include <pspaudio.h>
PSP_MODULE_INFO("OpenLara", 0, 1, 1);
PSP_HEAP_SIZE_KB(20480);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_VFPU);
//#define printf pspDebugScreenPrintf
//#define printf Kprintf
#include "game.h"
#define BUF_WIDTH (512)
#define SCR_WIDTH (480)
#define SCR_HEIGHT (272)
int exitCallback(int arg1, int arg2, void *common) {
Core::quit();
return 0;
}
int callbackThread(SceSize args, void *argp) {
int cbid = sceKernelCreateCallback("Exit Callback", exitCallback, NULL);
sceKernelRegisterExitCallback(cbid);
sceKernelSleepThreadCB();
return 0;
}
int setupCallbacks(void) {
int thid = sceKernelCreateThread("update_thread", callbackThread, 0x11, 0xFA0, 0, 0);
sceKernelStartThread(thid, 0, 0);
return thid;
}
int osStartTime = 0;
int osTimerFreq;
int osGetTime() {
u64 time;
sceRtcGetCurrentTick(&time);
return int(time * 1000 / osTimerFreq - osStartTime);
}
bool osSave(const char *name, const void *data, int size) {
return false;
}
int joyGetPOV(int mask) {
switch (mask) {
case 0b0001 : return 1;
case 0b1001 : return 2;
case 0b1000 : return 3;
case 0b1010 : return 4;
case 0b0010 : return 5;
case 0b0110 : return 6;
case 0b0100 : return 7;
case 0b0101 : return 8;
}
return 0;
}
void joyInit() {
sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
}
void joyUpdate() {
SceCtrlData pad;
sceCtrlReadBufferPositive(&pad, 1);
Input::setDown(ikJoyA, (pad.Buttons & PSP_CTRL_CROSS));
Input::setDown(ikJoyB, (pad.Buttons & PSP_CTRL_CIRCLE));
Input::setDown(ikJoyX, (pad.Buttons & PSP_CTRL_SQUARE));
Input::setDown(ikJoyY, (pad.Buttons & PSP_CTRL_TRIANGLE));
Input::setDown(ikJoyLB, (pad.Buttons & PSP_CTRL_LTRIGGER));
Input::setDown(ikJoyRB, (pad.Buttons & PSP_CTRL_RTRIGGER));
Input::setDown(ikJoyStart, (pad.Buttons & PSP_CTRL_START));
Input::setDown(ikJoySelect, (pad.Buttons & PSP_CTRL_SELECT));
int pov = joyGetPOV( ((pad.Buttons & PSP_CTRL_UP) != 0) |
(((pad.Buttons & PSP_CTRL_DOWN) != 0) << 1) |
(((pad.Buttons & PSP_CTRL_LEFT) != 0) << 2) |
(((pad.Buttons & PSP_CTRL_RIGHT) != 0) << 3));
Input::setPos(ikJoyPOV, vec2(float(pov), 0.0f));
vec2 stick = vec2(float(pad.Lx), float(pad.Ly)) / 128.0f - 1.0f;
if (fabsf(stick.x) < 0.2f && fabsf(stick.y) < 0.2f)
stick = vec2(0.0f);
Input::setPos(ikJoyR, stick);
}
void sndFill(void* buf, unsigned int length, void *userdata) {
Sound::fill((Sound::Frame*)buf, length);
}
void sndInit() {
pspAudioInit();
pspAudioSetChannelCallback(0, sndFill, NULL);
}
char Stream::cacheDir[255];
char Stream::contentDir[255];
int main() {
//pspDebugScreenInit();
setupCallbacks();
sceGuInit();
Core::beginCmdBuf();
sceGuDrawBuffer(GU_PSM_5650, (void*)0, BUF_WIDTH);
sceGuDispBuffer(SCR_WIDTH, SCR_HEIGHT, (void*)(BUF_WIDTH * SCR_HEIGHT * 2), BUF_WIDTH);
sceGuDepthBuffer((void*)(BUF_WIDTH * SCR_HEIGHT * 2 * 2), BUF_WIDTH);
sceGuScissor(0, 0, SCR_WIDTH, SCR_HEIGHT);
sceGuEnable(GU_SCISSOR_TEST);
sndInit();
joyInit();
osTimerFreq = sceRtcGetTickResolution();
osStartTime = osGetTime();
Game::init("PSXDATA/LEVEL2.PSX");
Core::submitCmdBuf();
sceDisplayWaitVblankStart();
sceGuDisplay(GU_TRUE);
Core::curBackBuffer = 0;
while (!Core::isQuit) {
//pspDebugScreenSetOffset((int)frameOffset);
//pspDebugScreenSetXY(0, 0);
Core::beginCmdBuf();
joyUpdate();
Game::update();
Game::render();
Core::submitCmdBuf();
//sceDisplayWaitVblankStart();
Core::curBackBuffer = sceGuSwapBuffers();
}
Game::deinit();
sceGuTerm();
sceKernelExitGame();
return 0;
}

View File

@@ -365,10 +365,7 @@ int main(int argc, char** argv) {
joyInit();
sndInit(hWnd);
char *lvlName = argc > 1 ? argv[1] : NULL;
char *sndName = argc > 2 ? argv[2] : NULL;
Game::init(lvlName, sndName);
Game::init(argc > 1 ? argv[1] : NULL);
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)&WndProc);
ShowWindow(hWnd, SW_SHOWDEFAULT);

View File

@@ -51,17 +51,29 @@ const char *UniformName[uMAX] = { SHADER_UNIFORMS(DECL_STR) };
#undef STR
struct Shader {
GLuint ID;
GLint uID[uMAX];
vec4 params[uMAX][4];
enum Type : GLint {
enum Type {
DEFAULT = 0,
/* shader */ SPRITE = 0, FLASH = 1, ROOM = 2, ENTITY = 3, MIRROR = 4,
/* filter */ FILTER_DOWNSAMPLE = 1, FILTER_GRAYSCALE = 2, FILTER_BLUR = 3, FILTER_MIXER = 4, FILTER_EQUIRECTANGULAR = 5,
/* water */ WATER_DROP = 0, WATER_STEP = 1, WATER_CAUSTICS = 2, WATER_MASK = 3, WATER_COMPOSE = 4,
MAX = 6
};
#ifdef FFP
Shader(const char *source, const char *defines = "") {}
virtual ~Shader() {}
bool bind() { return true; }
void setParam(UniformType uType, const int &value, int count = 1) {}
void setParam(UniformType uType, const float &value, int count = 1) {}
void setParam(UniformType uType, const vec2 &value, int count = 1) {}
void setParam(UniformType uType, const vec3 &value, int count = 1) {}
void setParam(UniformType uType, const vec4 &value, int count = 1) {}
void setParam(UniformType uType, const mat4 &value, int count = 1) {}
void setParam(UniformType uType, const Basis &value, int count = 1) {}
#else
uint32 ID;
int32 uID[uMAX];
Shader(const char *source, const char *defines = "") {
char fileName[255];
@@ -227,6 +239,7 @@ struct Shader {
if (uID[uType] != -1 && checkParam(uType, &value, sizeof(value) * count))
glUniform4fv(uID[uType], count * 2, (GLfloat*)&value);
}
#endif
};
#endif

View File

@@ -99,8 +99,8 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
vec4 coord;
coord.w = rBasisPos.w; // visible flag
#ifdef TYPE_SPRITE
coord.xyz = mulBasis(rBasisRot, rBasisPos.xyz + aCoord.xyz, vec3(aTexCoord.z, -aTexCoord.w, 0.0) * 32767.0);
#if defined(TYPE_SPRITE) && defined(ALIGN_SPRITES)
coord.xyz = mulBasis(rBasisRot, rBasisPos.xyz + aCoord.xyz, vec3(aTexCoord.z, aTexCoord.w, 0.0) * 32767.0);
#else
coord.xyz = mulBasis(rBasisRot, rBasisPos.xyz, aCoord.xyz);
#endif

View File

@@ -3,10 +3,12 @@
#define DECODE_VAG
#define DECODE_ADPCM
#define DECODE_OGG
#ifndef __EMSCRIPTEN__
#define DECODE_MP3
#ifndef _PSP
#define DECODE_OGG
#ifndef __EMSCRIPTEN__
#define DECODE_MP3
#endif
#endif
#include "utils.h"
@@ -436,7 +438,7 @@ namespace Sound {
uint32 fourcc;
stream->read(fourcc);
if (fourcc == FOURCC("RIFF")) { // wav
struct {
uint16 format;
uint16 channels;
@@ -452,7 +454,7 @@ namespace Sound {
stream->read(type);
stream->read(size);
if (type == FOURCC("fmt ")) {
stream->read(waveFmt);
stream->raw(&waveFmt, sizeof(waveFmt));
stream->seek(size - sizeof(waveFmt));
} else if (type == FOURCC("data")) {
if (waveFmt.format == 1) decoder = new PCM(stream, waveFmt.channels, waveFmt.samplesPerSec, size, waveFmt.sampleBits);
@@ -464,26 +466,28 @@ namespace Sound {
stream->seek(size);
}
}
#ifdef DECODE_OGG
else if (fourcc == FOURCC("OggS")) { // ogg
stream->seek(-4);
decoder = new OGG(stream, 2);
#ifdef DECODE_OGG
decoder = new OGG(stream, 2);
#endif
}
#endif
#ifdef DECODE_MP3
else if (fourcc == FOURCC("ID3\3")) { // mp3
decoder = new MP3(stream, 2);
#ifdef DECODE_MP3
decoder = new MP3(stream, 2);
#endif
}
#endif
#ifdef DECODE_VAG
else { // vag
stream->setPos(0);
decoder = new VAG(stream);
#ifdef DECODE_VAG
decoder = new VAG(stream);
#endif
}
#endif
if (!decoder)
delete stream;
isPlaying = decoder != NULL;
ASSERT(isPlaying);
}
~Sample() {
@@ -507,10 +511,10 @@ namespace Sound {
if (!(flags & PAN))
return vec2(1.0f);
mat4 m = Sound::listener.matrix;
vec3 v = pos - m.offset.xyz;
vec3 v = pos - m.offset().xyz();
float dist = max(0.0f, 1.0f - (v.length() / SND_FADEOFF_DIST));
float pan = m.right.xyz.dot(v.normal());
float pan = m.right().xyz().dot(v.normal());
float l = min(1.0f, 1.0f - pan);
float r = min(1.0f, 1.0f + pan);
@@ -525,7 +529,7 @@ namespace Sound {
while (i < count) {
int res = decoder->decode(&frames[i], count - i);
if (res == 0) {
if (!(flags & Flags::LOOP)) {
if (!(flags & LOOP)) {
isPlaying = false;
break;
} else
@@ -536,7 +540,7 @@ namespace Sound {
// apply volume
#define VOL_CONV(x) (1.0f - sqrtf(1.0f - x * x));
float m = ((flags & Flags::MUSIC) ? Core::settings.audio.music : Core::settings.audio.sound);
float m = ((flags & MUSIC) ? Core::settings.audio.music : Core::settings.audio.sound);
float v = volume * m;
vec2 pan = getPan();
vec2 vol = pan * VOL_CONV(v);
@@ -693,7 +697,7 @@ namespace Sound {
} entity;
stream->seek(sizeof(entity) * index);
stream->read(entity);
stream->raw(&entity, sizeof(entity));
stream->setPos(entity.offset);
return stream;
}
@@ -704,8 +708,8 @@ namespace Sound {
Stream *openCDAudioMP3(const char *dat, const char *name, int index = -1) {
if (!Stream::existsContent(dat) || !Stream::existsContent(name))
return NULL;
// TODO
return NULL;
Stream *stream = new Stream(name);
return stream;
}
Sample* play(Stream *stream, const vec3 &pos, float volume = 1.0f, float pitch = 0.0f, int flags = 0, int id = - 1) {

View File

@@ -53,7 +53,15 @@ struct Sprite : Controller {
}
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
Core::active.shader->setParam(uBasis, Basis(Core::mViewInv.getRot(), pos));
Basis b;
b.w = 1.0f;
b.pos = pos;
#ifdef MERGE_SPRITES
b.rot = Core::mViewInv.getRot();
#else
b.rot = quat(0, 0, 0, 1);
#endif
Core::setBasis(&b, 1);
mesh->renderSprite(-(getEntity().modelIndex + 1), frame);
}
};

View File

@@ -2,17 +2,89 @@
#define H_TEXTURE
#include "core.h"
#include "format.h"
struct Texture {
enum Format : uint32 { LUMINANCE, RGBA, RGB16, RGBA16, RGBA_FLOAT, RGBA_HALF, DEPTH, DEPTH_STENCIL, SHADOW, MAX };
enum Format { LUMINANCE, RGBA, RGB16, RGBA16, RGBA_FLOAT, RGBA_HALF, DEPTH, DEPTH_STENCIL, SHADOW, MAX };
enum Option { CUBEMAP = 1, MIPMAPS = 2, NEAREST = 4 };
GLuint ID;
int width, height, origWidth, origHeight;
Format format;
bool cube;
bool filter;
uint32 opt;
#ifdef _PSP
TR::Tile4 *tiles;
TR::CLUT *cluts;
uint8 *memory;
void swizzle(uint8* out, const uint8* in, uint32 width, uint32 height) {
int rowblocks = width / 16;
for (int j = 0; j < height; j++)
for (int i = 0; i < width; i++) {
int blockx = i / 16;
int blocky = j / 8;
int x = i - blockx * 16;
int y = j - blocky * 8;
int block_index = blockx + blocky * rowblocks;
int block_address = block_index * 16 * 8;
out[block_address + x + y * 16] = in[i + j * width];
}
}
#else
uint32 ID;
Texture *tiles[32];
#endif
#ifdef SPLIT_BY_TILE
#ifdef _PSP
Texture(TR::Tile4 *tiles, int tilesCount, TR::CLUT *cluts, int clutsCount) : width(256), height(256), memory(0) {
#ifdef EDRAM_TEX
this->tiles = (TR::Tile4*)Core::allocEDRAM(tilesCount * sizeof(tiles[0]));
this->cluts = (TR::CLUT*)Core::allocEDRAM(clutsCount * sizeof(cluts[0]));
memcpy(this->cluts, cluts, clutsCount * sizeof(cluts[0]));
#ifdef TEX_SWIZZLE
for (int i = 0; i < tilesCount; i++)
swizzle((uint8*)&this->tiles[i], (uint8*)&tiles[i], width / 2, height);
#else
memcpy(this->tiles, tiles, tilesCount * sizeof(tiles[0]));
#endif
#else
this->tiles = tiles;
this->cluts = cluts;
#endif
}
#else
Texture(TR::Tile32 *tiles, int tilesCount) : width(256), height(256), ID(0) {
memset(this->tiles, 0, sizeof(this->tiles));
ASSERT(tilesCount < COUNT(this->tiles));
for (int i = 0; i < tilesCount; i++)
this->tiles[i] = new Texture(width, height, RGBA, 0, tiles + i);
}
#endif
void bind(uint16 tile, uint16 clut) {
#ifdef _PSP
sceGuClutLoad(1, cluts + clut);
sceGuTexImage(0, width, height, width, tiles + tile);
#else
tiles[tile]->bind(0);
#endif
}
#endif
Texture(int width, int height, Format format, uint32 opt = 0, void *data = NULL) : opt(opt) {
#ifndef _PSP
#ifdef SPLIT_BY_TILE
memset(this->tiles, 0, sizeof(tiles));
#endif
#endif
Texture(int width, int height, Format format, bool cube = false, void *data = NULL, bool filter = true, bool mips = false) : cube(cube), filter(filter) {
if (!Core::support.texNPOT) {
width = nextPow2(width);
height = nextPow2(height);
@@ -20,10 +92,9 @@ struct Texture {
this->width = origWidth = width;
this->height = origHeight = height;
glGenTextures(1, &ID);
bind(0);
GLenum target = cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
bool filter = (opt & NEAREST) == 0;
bool cube = (opt & CUBEMAP) != 0;
bool mipmaps = (opt & MIPMAPS) != 0;
bool isShadow = format == SHADOW;
if (format == SHADOW && !Core::support.shadowSampler) {
@@ -54,6 +125,14 @@ struct Texture {
this->format = format;
#ifdef _PSP
memory = NULL;//new uint8[width * height * 2];
#else
glGenTextures(1, &ID);
bind(0);
GLenum target = (opt & CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
if (format == SHADOW) {
glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
@@ -67,7 +146,7 @@ struct Texture {
glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, color);
}
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter ? (mips ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) : ( mips ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST ));
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter ? (mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) : ( mipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST ));
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter ? GL_LINEAR : GL_NEAREST);
struct FormatDesc {
@@ -87,83 +166,127 @@ struct Texture {
FormatDesc desc = formats[format];
#ifdef __EMSCRIPTEN__ // fucking firefox!
if (format == RGBA_FLOAT) {
if (Core::support.texFloat) {
desc.ifmt = GL_RGBA;
desc.type = GL_FLOAT;
#ifdef __EMSCRIPTEN__ // fucking firefox!
if (format == RGBA_FLOAT) {
if (Core::support.texFloat) {
desc.ifmt = GL_RGBA;
desc.type = GL_FLOAT;
}
}
}
if (format == RGBA_HALF) {
if (Core::support.texHalf) {
if (format == RGBA_HALF) {
if (Core::support.texHalf) {
desc.ifmt = GL_RGBA;
#ifdef MOBILE
desc.type = GL_HALF_FLOAT_OES;
#endif
}
}
#else
if ((format == RGBA_FLOAT && !Core::support.colorFloat) || (format == RGBA_HALF && !Core::support.colorHalf)) {
desc.ifmt = GL_RGBA;
#ifdef MOBILE
desc.type = GL_HALF_FLOAT_OES;
if (format == RGBA_HALF)
desc.type = GL_HALF_FLOAT_OES;
#endif
}
}
#else
if ((format == RGBA_FLOAT && !Core::support.colorFloat) || (format == RGBA_HALF && !Core::support.colorHalf)) {
desc.ifmt = GL_RGBA;
#ifdef MOBILE
if (format == RGBA_HALF)
desc.type = GL_HALF_FLOAT_OES;
#endif
}
#endif
#endif
for (int i = 0; i < 6; i++) {
glTexImage2D(cube ? (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i) : GL_TEXTURE_2D, 0, desc.ifmt, width, height, 0, desc.fmt, desc.type, data);
if (!cube) break;
}
#endif
if (mips)
if (mipmaps)
generateMipMap();
this->filter = filter;
if (filter)
this->opt &= ~NEAREST;
else
this->opt |= NEAREST;
}
void generateMipMap() {
#ifdef _PSP
// TODO
#else
bind(0);
GLenum target = cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
GLenum target = (opt & CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
glGenerateMipmap(target);
if (!cube && filter && (Core::support.maxAniso > 0))
if (!(opt & CUBEMAP) && !(opt & NEAREST) && (Core::support.maxAniso > 0))
glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, min(int(Core::support.maxAniso), 8));
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);
#endif
}
virtual ~Texture() {
glDeleteTextures(1, &ID);
#ifdef _PSP
delete[] memory;
#else
#ifdef SPLIT_BY_TILE
if (!ID) {
for (int i = 0; i < COUNT(tiles); i++)
delete[] tiles[i];
return;
}
#endif
glDeleteTextures(1, &ID);
#endif
}
void setFilterQuality(Core::Settings::Quality value) {
bool filter = value > Core::Settings::LOW;
bool mips = value > Core::Settings::MEDIUM;
bool filter = value > Core::Settings::LOW;
bool mipmaps = value > Core::Settings::MEDIUM;
#ifdef _PSP
if (filter)
opt &= ~NEAREST;
else
opt |= NEAREST;
if (mipmaps)
opt |= MIPMAPS;
else
opt &= ~MIPMAPS;
#else
Core::active.textures[0] = NULL;
bind(0);
if (Core::support.maxAniso > 0)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, value > Core::Settings::MEDIUM ? min(int(Core::support.maxAniso), 8) : 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter ? (mips ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) : ( mips ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST ));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter ? (mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) : ( mipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST ));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter ? GL_LINEAR : GL_NEAREST);
#endif
}
void bind(int sampler) {
#ifdef _PSP
if (this && !sampler && memory)
sceGuTexImage(0, width, height, width, memory);
#else
#ifdef SPLIT_BY_TILE
if (sampler || !ID) return;
#endif
if (Core::active.textures[sampler] != this) {
Core::active.textures[sampler] = this;
glActiveTexture(GL_TEXTURE0 + sampler);
glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, ID);
glBindTexture((opt & CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, ID);
}
#endif
}
void unbind(int sampler) {
#ifdef _PSP
//
#else
if (Core::active.textures[sampler]) {
Core::active.textures[sampler] = NULL;
glActiveTexture(GL_TEXTURE0 + sampler);
glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, 0);
glBindTexture((opt & CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, 0);
}
#endif
}
struct Color24 {
@@ -201,10 +324,14 @@ struct Texture {
strcat(buf, ".bmp");
FILE *f = fopen(buf, "wb");
fwrite(&bmfh, sizeof(bmfh), 1, f);
fwrite(&BMIH, sizeof(BMIH), 1, f);
fwrite(data32, width * height * 4, 1, f);
fclose(f);
if (f) {
fwrite(&bmfh, sizeof(bmfh), 1, f);
fwrite(&BMIH, sizeof(BMIH), 1, f);
int res = fwrite(data32, width * height * 4, 1, f);
LOG("Res %d\n", res);
fclose(f);
} else
ASSERT(false);
}
*/
static uint8* LoadPCX(Stream &stream, uint32 &width, uint32 &height) {
@@ -669,7 +796,7 @@ struct Texture {
((uint32*)data)[y * dw] = ((uint32*)data)[y * dw + dw - 1] = 0xFF000000;
}
Texture *tex = new Texture(dw, dh, Texture::RGBA, false, data);
Texture *tex = new Texture(dw, dh, Texture::RGBA, 0, data);
tex->origWidth = width;
tex->origHeight = height;
@@ -829,8 +956,7 @@ struct Atlas {
fill(root, data);
fillInstances();
Texture *atlas = new Texture(width, height, Texture::RGBA, false, data, true, true);
Texture *atlas = new Texture(width, height, Texture::RGBA, Texture::MIPMAPS, data);
delete[] data;
return atlas;
};

View File

@@ -107,7 +107,7 @@ struct TrapDartEmitter : Controller {
game->addEntity(TR::Entity::DART, getRoomIndex(), p, angle.y);
if (level->extra.smoke != -1)
game->addEntity(TR::Entity::SMOKE, getRoomIndex(), p);
game->playSound(TR::SND_DART, p, Sound::Flags::PAN);
game->playSound(TR::SND_DART, p, Sound::PAN);
}
updateAnimation(true);
@@ -160,7 +160,7 @@ struct Flame : Sprite {
return;
}
pos = lara->animation.getJoints(lara->getMatrix(), jointIndex).pos;
pos = lara->getJoint(jointIndex).pos;
if (jointIndex == 0)
pos.y += 100.0f;
@@ -321,6 +321,7 @@ struct TrapBoulder : Controller {
if (onGround) {
pos = p;
deactivate(true);
game->checkTrigger(this, true);
return;
} else {
pos.x = p.x;
@@ -528,7 +529,7 @@ struct Door : Controller {
sectors[0] = level->getSector(roomIndex[0], x, z, sectorIndex[0]);
// behind
roomIndex[1] = level->getNextRoom(sectors[0].floorIndex);
roomIndex[1] = level->getNextRoom(&sectors[0]);
if (roomIndex[1] == TR::NO_ROOM)
return;
@@ -698,7 +699,7 @@ struct Crystal : Controller {
Texture *environment;
Crystal(IGame *game, int entity) : Controller(game, entity) {
environment = new Texture(64, 64, Texture::RGBA, true, NULL, true, true);
environment = new Texture(64, 64, Texture::RGBA, Texture::CUBEMAP | Texture::MIPMAPS);
activate();
}
@@ -713,7 +714,7 @@ struct Crystal : Controller {
virtual void update() {
updateAnimation(false);
vec3 lightPos = animation.getJoints(getMatrix(), 0, false).pos - vec3(0, 256, 0);
vec3 lightPos = getJoint(0).pos - vec3(0, 256, 0);
getRoom().addDynLight(entity, vec4(lightPos, 0.0f), CRYSTAL_LIGHT_COLOR);
}
@@ -740,7 +741,7 @@ struct CrystalPickup : Controller {
virtual void update() {
updateAnimation(false);
vec3 lightPos = animation.getJoints(getMatrix(), 0, false).pos;
vec3 lightPos = getJoint(0).pos;
getRoom().addDynLight(entity, vec4(lightPos, 0.0f), CRYSTAL_PICKUP_LIGHT_COLOR);
}
};
@@ -1001,7 +1002,7 @@ struct Lightning : Controller {
} else if (!hasTargets) {
target = pos + vec3(0.0f, 1024.0f, 0.0f);
} else
target = animation.getJoints(getMatrix(), 1 + int(randf() * 5)).pos;
target = getJoint(1 + int(randf() * 5)).pos;
}
game->playSound(TR::SND_LIGHTNING, pos, Sound::PAN);
}
@@ -1028,10 +1029,10 @@ struct Lightning : Controller {
void setVertex(Vertex &v, const vec3 &coord, int16 joint, int idx) {
v.coord = toCoord(coord, joint);
v.normal = { 0, -1, 0, 0 };
v.texCoord = { barTile[0].texCoord[idx].x, barTile[0].texCoord[idx].y, 32767, 32767 };
v.param = { 0, 0, 0, 0 };
v.color = { 255, 255, 255, 255 };
v.normal = short4( 0, -1, 0, 0 );
v.texCoord = short4( barTile[0].texCoord[idx].x, barTile[0].texCoord[idx].y, 32767, 32767 );
v.param = ubyte4( 0, 0, 0, 0 );
v.color = ubyte4( 255, 255, 255, 255 );
}
void renderPolyline(const vec3 &start, const vec3 &end, float width, float spread, int depth) {
@@ -1061,7 +1062,7 @@ struct Lightning : Controller {
ASSERT(vCount == count * 2);
// build vertices
vec3 dir = Core::mViewInv.dir.xyz;
vec3 dir = Core::mViewInv.dir().xyz();
vCount = 0;
vec3 n;
@@ -1096,7 +1097,7 @@ struct Lightning : Controller {
if (!armed)
target = game->getLara()->pos;
Basis b = animation.getJoints(getMatrix(), 0);
Basis b = getJoint(0);
b.rot = quat(0, 0, 0, 1);
game->setShader(Core::pass, Shader::FLASH, false, false);
@@ -1166,7 +1167,7 @@ struct TrapLava : Controller {
vec3 dir = getDir();
roomIndex = getRoomIndex();
TR::Room::Sector *s = level->getSector(roomIndex, int(pos.x + dir.x * 2048.0f), int(pos.y), int(pos.z + dir.z * 2048.0f));
TR::Room::Sector *s = level->getSector(roomIndex, pos + dir * 2048.0f);
if (!s || s->floor * 256 != int(pos.y))
return;
@@ -1469,7 +1470,7 @@ struct StoneItem : Controller {
float s = 0.3f + (sinf(phase * PI2) * 0.5f + 0.5f) * 0.7f;
vec4 lightColor(0.1f * s, 1.0f * s, 1.0f * s, 1.0f / STONE_ITEM_LIGHT_RADIUS);
vec3 lightPos = animation.getJoints(getMatrix(), 0, false).pos;
vec3 lightPos = getJoint(0).pos;
getRoom().addDynLight(entity, vec4(lightPos, 0.0f), lightColor);
}

View File

@@ -164,9 +164,10 @@ namespace UI {
bool showHelp;
const static uint8 char_width[110] = {
14, 11, 11, 11, 11, 11, 11, 13, 8, 11, 12, 11, 13, 13, 12, 11, 12, 12, 11, 12, 13, 13, 13, 12,
12, 11, 9, 9, 9, 9, 9, 9, 9, 9, 5, 9, 9, 5, 12, 10, 9, 9, 9, 8, 9, 8, 9, 9, 11, 9, 9, 9, 12, 8,
10, 10, 10, 10, 10, 9, 10, 10, 5, 5, 5, 11, 9, 10, 8, 6, 6, 7, 7, 3, 11, 8, 13, 16, 9, 4, 12, 12,
14, 11, 11, 11, 11, 11, 11, 13, 8, 11, 12, 11, 13, 13, 12, 11, 12, 12, 11, 12, 13, 13, 13, 12, 12, 11, // A-Z
9, 9, 9, 9, 9, 9, 9, 9, 5, 9, 9, 5, 12, 10, 9, 9, 9, 8, 9, 8, 9, 9, 11, 9, 9, 9, // a-z
12, 8, 10, 10, 10, 10, 10, 9, 10, 10, // 0-9
5, 5, 5, 11, 9, 10, 8, 6, 6, 7, 7, 3, 11, 8, 13, 16, 9, 4, 12, 12,
7, 5, 7, 7, 7, 7, 7, 7, 7, 7, 16, 14, 14, 14, 16, 16, 16, 16, 16, 12, 14, 8, 8, 8, 8, 8, 8, 8 };
static const uint8 char_map[102] = {
@@ -216,13 +217,17 @@ namespace UI {
BAR_MAX,
};
struct {
struct Buffer {
Vertex vertices[MAX_CHARS * 4];
Index indices[MAX_CHARS * 6];
int iCount;
int vCount;
} buffer;
#ifdef SPLIT_BY_TILE
uint16 curTile, curClut;
#endif
void begin() {
Core::setDepthTest(false);
Core::setBlending(bmAlpha);
@@ -231,17 +236,30 @@ namespace UI {
float aspect = float(Core::width) / float(Core::height);
width = 480 * aspect;
Core::mViewProj = mat4(0.0f, width, 480, 0.0f, 0.0f, 1.0f);
Core::mProj = mat4(0.0f, width, 480, 0.0f, 0.0f, 1.0f);
Core::mView.identity();
Core::mModel.identity();
Core::setViewProj(Core::mView, Core::mProj);
game->setShader(Core::passGUI, Shader::DEFAULT);
Core::active.shader->setParam(uMaterial, vec4(1));
Core::setMaterial(1, 1, 1, 1);
Core::active.shader->setParam(uPosScale, vec4(0, 0, 1, 1));
buffer.iCount = buffer.vCount = 0;
#ifdef SPLIT_BY_TILE
curTile = curClut = 0xFFFF;
#endif
}
void flush() {
if (buffer.iCount > 0) {
#ifdef SPLIT_BY_TILE
if (curTile != 0xFFFF)
game->getAtlas()->bind(curTile, curClut);
#endif
game->getMesh()->renderBuffer(buffer.indices, buffer.iCount, buffer.vertices, buffer.vCount);
buffer.iCount = buffer.vCount = 0;
}
@@ -319,6 +337,19 @@ namespace UI {
}
}
#ifdef SPLIT_BY_TILE
if (sprite.tile != curTile
#ifdef SPLIT_BY_CLUT
|| sprite.clut != curClut
#endif
) {
flush();
curTile = sprite.tile;
curClut = sprite.clut;
}
#endif
mesh->addSprite(buffer.indices, buffer.vertices, buffer.iCount, buffer.vCount, 0, x, y, 0, sprite, tColor, bColor, true);
x += char_width[frame] + 1;
@@ -339,6 +370,19 @@ namespace UI {
flush();
TR::SpriteTexture &sprite = level->spriteTextures[level->spriteSequences[seq].sStart + specChar];
#ifdef SPLIT_BY_TILE
if (sprite.tile != curTile
#ifdef SPLIT_BY_CLUT
|| sprite.clut != curClut
#endif
) {
flush();
curTile = sprite.tile;
curClut = sprite.clut;
}
#endif
mesh->addSprite(buffer.indices, buffer.vertices, buffer.iCount, buffer.vCount, 0, int(pos.x), int(pos.y), 0, sprite, TR::Color32(255, 255, 255, 255), TR::Color32(255, 255, 255, 255), true);
}

View File

@@ -30,11 +30,32 @@
#endif
#ifdef ANDROID
#include <android/log.h>
#undef LOG
#define LOG(...) __android_log_print(ANDROID_LOG_INFO,"OpenLara",__VA_ARGS__)
#include <android/log.h>
#undef LOG
#define LOG(...) __android_log_print(ANDROID_LOG_INFO,"OpenLara",__VA_ARGS__)
#endif
#ifdef _PSP
extern "C" {
// pspmath.h
extern float vfpu_sinf(float x);
extern float vfpu_cosf(float x);
extern float vfpu_atan2f(float x, float y);
extern void vfpu_sincos(float r, float *s, float *c);
}
#define sinf(x) vfpu_sinf(x)
#define cosf(x) vfpu_cosf(x)
#define atan2f(x, y) vfpu_atan2f(x, y)
#define sincos(a, s, c) vfpu_sincos(a, s, c)
#else
void sincos(float r, float *s, float *c) {
*s = sinf(r);
*c = cosf(r);
}
#endif
extern int osGetTime();
extern bool osSave(const char *name, const void *data, int size);
@@ -167,6 +188,30 @@ uint32 fnv32(const char *data, int32 size, uint32 hash = 0x811c9dc5) {
return hash;
}
template <class T>
void qsort(T* v, int L, int R) {
int i = L;
int j = R;
const T m = v[(L + R) / 2];
while (i <= j) {
while (T::cmp(v[i], m) < 0) i++;
while (T::cmp(m, v[j]) < 0) j--;
if (i <= j)
swap(v[i++], v[j--]);
}
if (L < j) qsort(v, L, j);
if (i < R) qsort(v, i, R);
}
template <class T>
void sort(T *items, int count) {
if (count)
qsort(items, 0, count - 1);
}
struct vec2 {
float x, y;
vec2() {}
@@ -210,14 +255,11 @@ struct vec2 {
vec2 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); }
float angle() const { return atan2f(y, x); }
vec2& rotate(const vec2 &cs) { *this = vec2(x*cs.x - y*cs.y, x*cs.y + y*cs.x); return *this; }
vec2& rotate(float angle) { return rotate(vec2(cosf(angle), sinf(angle))); }
vec2& rotate(float angle) { vec2 cs; sincos(angle, &cs.y, &cs.x); return rotate(cs); }
};
struct vec3 {
union {
struct { float x, y, z; };
struct { vec2 xy; };
};
float x, y, z;
vec3() {}
vec3(float s) : x(s), y(s), z(s) {}
@@ -225,6 +267,9 @@ struct vec3 {
vec3(const vec2 &xy, float z = 0.0f) : x(xy.x), y(xy.y), z(z) {}
vec3(float lng, float lat) : x(sinf(lat) * cosf(lng)), y(-sinf(lng)), z(cosf(lat) * cosf(lng)) {}
vec2& xy() const { return *((vec2*)&x); }
vec2& yz() const { return *((vec2*)&y); }
inline float& operator [] (int index) const { ASSERT(index >= 0 && index <= 2); return ((float*)this)[index]; }
inline bool operator == (const vec3 &v) const { return x == v.x && y == v.y && z == v.z; }
@@ -273,7 +318,8 @@ struct vec3 {
}
vec3 rotateY(float angle) const {
float s = sinf(angle), c = cosf(angle);
float s, c;
sincos(angle, &s, &c);
return vec3(x*c - z*s, y, x*s + z*c);
}
@@ -285,11 +331,9 @@ struct vec3 {
};
struct vec4 {
union {
struct { float x, y, z, w; };
struct { vec2 xy, zw; };
struct { vec3 xyz; };
};
float x, y, z, w;
vec3& xyz() const { return *((vec3*)&x); }
vec4() {}
vec4(float s) : x(s), y(s), z(s), w(s) {}
@@ -314,21 +358,20 @@ struct vec4 {
};
struct quat {
union {
struct { float x, y, z, w; };
struct { vec3 xyz; };
};
float x, y, z, w;
vec3& xyz() const { return *((vec3*)&x); }
quat() {}
quat(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
quat(const vec3 &axis, float angle) {
angle *= 0.5f;
float s = sinf(angle);
float s, c;
sincos(angle * 0.5f, &s, &c);
x = axis.x * s;
y = axis.y * s;
z = axis.z * s;
w = cosf(angle);
w = c;
}
quat operator - () const {
@@ -355,8 +398,8 @@ struct quat {
}
vec3 operator * (const vec3 &v) const {
// return v + xyz.cross(xyz.cross(v) + v * w) * 2.0f;
return (*this * quat(v.x, v.y, v.z, 0) * inverse()).xyz;
//return v + xyz.cross(xyz.cross(v) + v * w) * 2.0f;
return (*this * quat(v.x, v.y, v.z, 0) * inverse()).xyz();
}
float dot(const quat &q) const {
@@ -424,16 +467,15 @@ struct quat {
};
struct mat4 {
float e00, e10, e20, e30,
e01, e11, e21, e31,
e02, e12, e22, e32,
e03, e13, e23, e33;
union {
struct {
float e00, e10, e20, e30,
e01, e11, e21, e31,
e02, e12, e22, e32,
e03, e13, e23, e33;
};
struct { vec4 right, up, dir, offset; };
};
vec4& right() const { return *((vec4*)&e00); }
vec4& up() const { return *((vec4*)&e01); }
vec4& dir() const { return *((vec4*)&e02); }
vec4& offset() const { return *((vec4*)&e03); }
mat4() {}
@@ -485,10 +527,10 @@ struct mat4 {
r = up.cross(d).normal();
u = d.cross(r);
this->right = vec4(r, 0.0f);
this->up = vec4(u, 0.0f);
this->dir = vec4(d, 0.0f);
this->offset = vec4(from, 1.0f);
this->right() = vec4(r, 0.0f);
this->up() = vec4(u, 0.0f);
this->dir() = vec4(d, 0.0f);
this->offset() = vec4(from, 1.0f);
}
mat4(const vec4 &reflectPlane) {
@@ -497,10 +539,10 @@ struct mat4 {
c = reflectPlane.z,
d = reflectPlane.w;
right = vec4(1 - 2*a*a, - 2*b*a, - 2*c*a, 0);
up = vec4( - 2*a*b, 1 - 2*b*b, - 2*c*b, 0);
dir = vec4( - 2*a*c, - 2*b*c, 1 - 2*c*c, 0);
offset = vec4( - 2*a*d, - 2*b*d, - 2*c*d, 1);
right() = vec4(1 - 2*a*a, - 2*b*a, - 2*c*a, 0);
up() = vec4( - 2*a*b, 1 - 2*b*b, - 2*c*b, 0);
dir() = vec4( - 2*a*c, - 2*b*c, 1 - 2*c*c, 0);
offset() = vec4( - 2*a*d, - 2*b*d, - 2*c*d, 1);
}
@@ -564,7 +606,8 @@ struct mat4 {
void rotateX(float angle) {
mat4 m;
m.identity();
float s = sinf(angle), c = cosf(angle);
float s, c;
sincos(angle, &s, &c);
m.e11 = c; m.e21 = s;
m.e12 = -s; m.e22 = c;
*this = *this * m;
@@ -573,7 +616,8 @@ struct mat4 {
void rotateY(float angle) {
mat4 m;
m.identity();
float s = sinf(angle), c = cosf(angle);
float s, c;
sincos(angle, &s, &c);
m.e00 = c; m.e20 = -s;
m.e02 = s; m.e22 = c;
*this = *this * m;
@@ -582,12 +626,91 @@ struct mat4 {
void rotateZ(float angle) {
mat4 m;
m.identity();
float s = sinf(angle), c = cosf(angle);
float s, c;
sincos(angle, &s, &c);
m.e00 = c; m.e01 = -s;
m.e10 = s; m.e11 = c;
*this = *this * m;
}
void rotateYXZ(const vec3 &angle) {
float s, c, a, b;
if (angle.y != 0.0f) {
sincos(angle.y, &s, &c);
a = e00 * c - e02 * s;
b = e02 * c + e00 * s;
e00 = a;
e02 = b;
a = e10 * c - e12 * s;
b = e12 * c + e10 * s;
e10 = a;
e12 = b;
a = e20 * c - e22 * s;
b = e22 * c + e20 * s;
e20 = a;
e22 = b;
}
if (angle.x != 0.0f) {
sincos(angle.x, &s, &c);
a = e01 * c + e02 * s;
b = e02 * c - e01 * s;
e01 = a;
e02 = b;
a = e11 * c + e12 * s;
b = e12 * c - e11 * s;
e11 = a;
e12 = b;
a = e21 * c + e22 * s;
b = e22 * c - e21 * s;
e21 = a;
e22 = b;
}
if (angle.z != 0.0f) {
sincos(angle.z, &s, &c);
a = e00 * c + e01 * s;
b = e01 * c - e00 * s;
e00 = a;
e01 = b;
a = e10 * c + e11 * s;
b = e11 * c - e10 * s;
e10 = a;
e11 = b;
a = e20 * c + e21 * s;
b = e21 * c - e20 * s;
e20 = a;
e21 = b;
}
}
void lerp(const mat4 &m, float t) {
e00 += (m.e00 - e00) * t;
e01 += (m.e01 - e01) * t;
e02 += (m.e02 - e02) * t;
e03 += (m.e03 - e03) * t;
e10 += (m.e10 - e10) * t;
e11 += (m.e11 - e11) * t;
e12 += (m.e12 - e12) * t;
e13 += (m.e13 - e13) * t;
e20 += (m.e20 - e20) * t;
e21 += (m.e21 - e21) * t;
e22 += (m.e22 - e22) * t;
e23 += (m.e23 - e23) * t;
}
float det() const {
return e00 * (e11 * (e22 * e33 - e32 * e23) - e21 * (e12 * e33 - e32 * e13) + e31 * (e12 * e23 - e22 * e13)) -
e10 * (e01 * (e22 * e33 - e32 * e23) - e21 * (e02 * e33 - e32 * e03) + e31 * (e02 * e23 - e22 * e03)) +
@@ -675,11 +798,11 @@ struct mat4 {
}
vec3 getPos() const {
return offset.xyz;
return offset().xyz();
}
void setPos(const vec3 &pos) {
offset.xyz = pos;
offset().xyz() = pos;
}
};
@@ -733,10 +856,16 @@ struct ubyte2 {
struct ubyte4 {
uint8 x, y, z, w;
ubyte4() {}
ubyte4(uint8 x, uint8 y, uint8 z, uint8 w) : x(x), y(y), z(z), w(w) {}
};
struct short2 {
int16 x, y;
short2() {}
short2(int16 x, int16 y) : x(x), y(y) {}
};
struct short3 {
@@ -766,17 +895,16 @@ struct short4 {
inline int16& operator [] (int index) const { ASSERT(index >= 0 && index <= 3); return ((int16*)this)[index]; }
};
quat rotYXZ(const vec3 &a) {
quat rotYXZ(const vec3 &angle) {
mat4 m;
m.identity();
m.rotateY(a.y);
m.rotateX(a.x);
m.rotateZ(a.z);
m.rotateYXZ(angle);
return m.getRot();
}
quat lerpAngle(const vec3 &a, const vec3 &b, float t) { // TODO: optimization
return rotYXZ(a).slerp(rotYXZ(b), t).normal();
return rotYXZ(a).lerp(rotYXZ(b), t);//.normal();
}
vec3 boxNormal(int x, int z) {
@@ -890,7 +1018,7 @@ struct Box {
Box res(vec3(+INF), vec3(-INF));
for (int i = 0; i < 8; i++) {
vec4 v = m * vec4((*this)[i], 1.0f);
res += v.xyz /= v.w;
res += v.xyz() /= v.w;
}
return res;
}
@@ -1000,7 +1128,7 @@ struct Box {
bool intersect(const mat4 &matrix, const vec3 &rayPos, const vec3 &rayDir, float &t) const {
mat4 mInv = matrix.inverse();
return intersect(mInv * rayPos, (mInv * vec4(rayDir, 0)).xyz, t);
return intersect(mInv * rayPos, (mInv * vec4(rayDir, 0)).xyz(), t);
}
};