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:
@@ -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;
|
||||
}
|
||||
|
||||
|
17
src/cache.h
17
src/cache.h
@@ -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;
|
||||
|
19
src/camera.h
19
src/camera.h
@@ -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;
|
||||
}
|
||||
};
|
||||
|
@@ -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) {
|
||||
|
@@ -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];
|
||||
|
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
456
src/core.h
456
src/core.h
@@ -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;
|
||||
}
|
||||
|
39
src/debug.h
39
src/debug.h
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
769
src/format.h
769
src/format.h
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
21
src/game.h
21
src/game.h
@@ -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
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
109
src/inventory.h
109
src/inventory.h
@@ -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);
|
||||
|
100
src/lara.h
100
src/lara.h
@@ -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) {
|
||||
|
142
src/level.h
142
src/level.h
@@ -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;
|
||||
|
821
src/mesh.h
821
src/mesh.h
File diff suppressed because it is too large
Load Diff
BIN
src/platform/psp/ICON0.PNG
Normal file
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
23
src/platform/psp/Makefile
Normal 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
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
165
src/platform/psp/main.cpp
Normal 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;
|
||||
}
|
@@ -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);
|
||||
|
19
src/shader.h
19
src/shader.h
@@ -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
|
||||
|
@@ -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
|
||||
|
48
src/sound.h
48
src/sound.h
@@ -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) {
|
||||
|
10
src/sprite.h
10
src/sprite.h
@@ -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);
|
||||
}
|
||||
};
|
||||
|
218
src/texture.h
218
src/texture.h
@@ -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;
|
||||
};
|
||||
|
@@ -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(§ors[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);
|
||||
}
|
||||
|
56
src/ui.h
56
src/ui.h
@@ -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);
|
||||
}
|
||||
|
||||
|
232
src/utils.h
232
src/utils.h
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user