Smudged vertices (#300)
* implements vertex shading and smudging Co-authored-by: Anonymous Maarten <madebr@users.noreply.github.com>
This commit is contained in:
parent
dd6a7cbc6f
commit
1a0301b6ee
|
|
@ -20,6 +20,8 @@ pm_temp_edge* pm_edge_table;
|
|||
|
||||
#define PREP_ALIGN(f) (f)
|
||||
|
||||
#define MODF_USES_DEFAULT 0x8000
|
||||
|
||||
// IDA: int __usercall addEdge@<EAX>(br_uint_16 first@<EAX>, br_uint_16 last@<EDX>)
|
||||
int addEdge(br_uint_16 first, br_uint_16 last) {
|
||||
pm_temp_edge* tep;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#define BR_COLOUR_RGB(r, g, b) \
|
||||
((((unsigned int)(r)) << 16) | (((unsigned int)(g)) << 8) | ((unsigned int)(b)))
|
||||
|
||||
#define BR_ALPHA(c) (((c) >> 24) & 0xFF)
|
||||
|
||||
#define BR_ANGLE_DEG(deg) ((br_angle)((deg)*182))
|
||||
#define BR_ANGLE_RAD(rad) ((br_angle)((rad)*10430))
|
||||
|
||||
|
|
|
|||
|
|
@ -2997,19 +2997,24 @@ enum {
|
|||
* Bits for br_model->flags
|
||||
*/
|
||||
enum {
|
||||
BR_MODF_DONT_WELD = 0x0001, /* Vertices with same x,y,z cannot be merged */
|
||||
BR_MODF_KEEP_ORIGINAL = 0x0002, /* Don't release model->faces/vertices during ModelUpdate() */
|
||||
BR_MODF_GENERATE_TAGS = 0x0004, /* Allocate and fill in the face and vertex tag structures */
|
||||
BR_MODF_QUICK_UPDATE = 0x0010, /* ModelUpdate is fast - but may produce slower models */
|
||||
BR_MODF_CUSTOM = 0x0020, /* Invoke custom callback for this model */
|
||||
BR_MODF_PREPREPARED = 0x0040, /* Model structure is pre-prepared - update performs no work */
|
||||
BR_MODF_UPDATEABLE = 0x0080, /* Added by Jeff from Errols code */
|
||||
BR_MODF_CREASE = 0x0100, /* Create creases in smoothing along edges if face<->face angle is g.t model->crease */
|
||||
BR_MODF_CUSTOM_NORMALS = 0x0200, /* Uses vertex normals from br_vertex structure */
|
||||
BR_MODF_CUSTOM_BOUNDS = 0x0400, /* Bounding box is already set up */
|
||||
// BR_MODF_FACES_ONLY = 0x0800, /* Model will only be used to render faces (not edges or points) */
|
||||
BR_MODF_DONT_WELD = 0x0001, /* Vertices with same x,y,z cannot be merged */
|
||||
BR_MODF_KEEP_ORIGINAL = 0x0002, /* Don't release model->faces/vertices during ModelUpdate() */
|
||||
BR_MODF_GENERATE_TAGS = 0x0004, /* Allocate and fill in the face and vertex tag structures */
|
||||
BR_MODF_QUICK_UPDATE = 0x0010, /* ModelUpdate is fast - but may produce slower models */
|
||||
BR_MODF_CUSTOM = 0x0020, /* Invoke custom callback for this model */
|
||||
BR_MODF_PREPREPARED = 0x0040, /* Model structure is pre-prepared - update performs no work */
|
||||
BR_MODF_UPDATEABLE = 0x0080, /* Added by Jeff from Errols code */
|
||||
BR_MODF_CREASE = 0x0100, /* Create creases in smoothing along edges if face<->face angle is g.t model->crease */
|
||||
BR_MODF_CUSTOM_NORMALS = 0x0200, /* Uses vertex normals from br_vertex structure */
|
||||
BR_MODF_CUSTOM_BOUNDS = 0x0400, /* Bounding box is already set up */
|
||||
BR_MODF_FACES_ONLY = 0x0800, /* Model will only be used to render faces (not edges or points) */
|
||||
BR_MODF_USED_PREPARED_USER = 0x1000, /* User fields in prepared data used */
|
||||
BR_MODF_CUSTOM_EQUATIONS = 0x2000, /* Uses face equations from br_face structure */
|
||||
_BR_MODF_RESERVED = 0x8000,
|
||||
|
||||
// Added by dethrace to force the vertex data to be reuploaded to GPU
|
||||
BR_MODF_DETHRACE_FORCE_BUFFER_UPDATE = 0x4000
|
||||
|
||||
MODF_USES_DEFAULT = 0x8000
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@
|
|||
#include "pedestrn.h"
|
||||
#include "replay.h"
|
||||
#include "skidmark.h"
|
||||
#include "sound.h"
|
||||
#include "spark.h"
|
||||
#include "sys.h"
|
||||
#include "sound.h"
|
||||
#include "utility.h"
|
||||
#include "world.h"
|
||||
#include <stdlib.h>
|
||||
|
|
@ -88,7 +88,7 @@ tU8* gPipe_buffer_oldest;
|
|||
tU32 gPipe_buffer_size;
|
||||
tU8* gLocal_buffer;
|
||||
tU32 gLocal_buffer_size;
|
||||
tPipe_chunk *gIncidentChunk; // FIXME: added by DethRace (really needed?)
|
||||
tPipe_chunk* gIncidentChunk; // FIXME: added by DethRace (really needed?)
|
||||
|
||||
#define LOCAL_BUFFER_SIZE 15000
|
||||
|
||||
|
|
@ -153,8 +153,7 @@ int IsActionReplayAvailable() {
|
|||
int SomeReplayLeft() {
|
||||
LOG_TRACE("()");
|
||||
|
||||
return ((GetReplayDirection() >= 1 && gPipe_play_ptr != gPipe_record_ptr) ||
|
||||
(GetReplayDirection() <= -1 && gPipe_play_ptr != gPipe_buffer_oldest));
|
||||
return ((GetReplayDirection() >= 1 && gPipe_play_ptr != gPipe_record_ptr) || (GetReplayDirection() <= -1 && gPipe_play_ptr != gPipe_buffer_oldest));
|
||||
}
|
||||
|
||||
// IDA: void __cdecl DisablePipedSounds()
|
||||
|
|
@ -179,7 +178,7 @@ tU32 LengthOfSession(tPipe_session* pSession) {
|
|||
LOG_TRACE("(%p)", pSession);
|
||||
|
||||
#define SIZEOF_CHUNK(MEMBER) (offsetof(tPipe_chunk, chunk_data) + sizeof(pSession->chunks.chunk_data.MEMBER))
|
||||
#define ROUND_UP(V, M) (((V) + (M) - 1) & (~((M) - 1)))
|
||||
#define ROUND_UP(V, M) (((V) + (M)-1) & (~((M)-1)))
|
||||
|
||||
switch (pSession->chunk_type) {
|
||||
case ePipe_chunk_actor_rstyle:
|
||||
|
|
@ -1551,12 +1550,12 @@ int ApplyPipedSession(tU8** pPtr) {
|
|||
if (*pPtr == gPipe_record_ptr) {
|
||||
return 1;
|
||||
}
|
||||
gEnd_of_session = *pPtr + (LengthOfSession((tPipe_session *)*pPtr) - sizeof(tU16));
|
||||
REPLAY_DEBUG_ASSERT(((tPipe_session *)*pPtr)->magic1 == REPLAY_DEBUG_MAGIC1);
|
||||
chunk_ptr = (tPipe_chunk *)(*pPtr + offsetof(tPipe_session, chunks));
|
||||
gEnd_of_session = *pPtr + (LengthOfSession((tPipe_session*)*pPtr) - sizeof(tU16));
|
||||
REPLAY_DEBUG_ASSERT(((tPipe_session*)*pPtr)->magic1 == REPLAY_DEBUG_MAGIC1);
|
||||
chunk_ptr = (tPipe_chunk*)(*pPtr + offsetof(tPipe_session, chunks));
|
||||
return_value = 0;
|
||||
chunk_type = ((tPipe_session *)*pPtr)->chunk_type;
|
||||
for (i = 0; i < ((tPipe_session *)*pPtr)->number_of_chunks; i++) {
|
||||
chunk_type = ((tPipe_session*)*pPtr)->chunk_type;
|
||||
for (i = 0; i < ((tPipe_session*)*pPtr)->number_of_chunks; i++) {
|
||||
switch (chunk_type) {
|
||||
case ePipe_chunk_model_geometry:
|
||||
ApplyModelGeometry(&chunk_ptr);
|
||||
|
|
@ -1630,9 +1629,9 @@ int ApplyPipedSession(tU8** pPtr) {
|
|||
}
|
||||
}
|
||||
#if defined(DETHRACE_FIX_BUGS)
|
||||
*pPtr += PIPE_ALIGN(LengthOfSession((tPipe_session *)*pPtr));
|
||||
*pPtr += PIPE_ALIGN(LengthOfSession((tPipe_session*)*pPtr));
|
||||
#else
|
||||
*pPtr += LengthOfSession((tPipe_session *)*pPtr);
|
||||
*pPtr += LengthOfSession((tPipe_session*)*pPtr);
|
||||
#endif
|
||||
if (*pPtr >= gPipe_buffer_working_end && *pPtr != gPipe_record_ptr) {
|
||||
*pPtr = gPipe_buffer_start;
|
||||
|
|
@ -1749,8 +1748,7 @@ void UndoPedestrian(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
|
|||
temp_prev_chunk = pPrev_chunk;
|
||||
if (pPrev_chunk == NULL) {
|
||||
ApplyPedestrian(pChunk);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
gDisable_advance = 1;
|
||||
ApplyPedestrian(&temp_prev_chunk);
|
||||
gDisable_advance = 0;
|
||||
|
|
@ -1775,8 +1773,7 @@ void UndoCar(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
|
|||
temp_prev_chunk = pPrev_chunk;
|
||||
if (pPrev_chunk == NULL) {
|
||||
ApplyCar(pChunk);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
gDisable_advance = 1;
|
||||
ApplyCar(&temp_prev_chunk);
|
||||
gDisable_advance = 0;
|
||||
|
|
@ -1788,7 +1785,7 @@ void UndoCar(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
|
|||
void UndoSound(tPipe_chunk** pChunk) {
|
||||
LOG_TRACE("(%p)", pChunk);
|
||||
|
||||
AdvanceChunkPtr(pChunk,ePipe_chunk_sound);
|
||||
AdvanceChunkPtr(pChunk, ePipe_chunk_sound);
|
||||
}
|
||||
|
||||
// IDA: void __usercall UndoDamage(tPipe_chunk **pChunk@<EAX>)
|
||||
|
|
@ -1799,8 +1796,7 @@ void UndoDamage(tPipe_chunk** pChunk) {
|
|||
|
||||
if (((*pChunk)->subject_index & 0xff00) == 0) {
|
||||
car = &gProgram_state.current_car;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
car = GetCarSpec((*pChunk)->subject_index >> 8, (*pChunk)->subject_index & 0xff);
|
||||
}
|
||||
for (i = 0; i < COUNT_OF(car->damage_units); i++) {
|
||||
|
|
@ -1885,8 +1881,7 @@ void UndoScreenWobble(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
|
|||
gDisable_advance = 1;
|
||||
if (pPrev_chunk == NULL) {
|
||||
SetScreenWobble(0, 0);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ApplyScreenWobble(&temp_prev_chunk);
|
||||
}
|
||||
gDisable_advance = 0;
|
||||
|
|
@ -1959,8 +1954,7 @@ void UndoSplash(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
|
|||
gDisable_advance = 1;
|
||||
if (pPrev_chunk == NULL) {
|
||||
((((*pChunk)->subject_index & 0xff00) == 0) ? &gProgram_state.current_car : GetCarSpec((*pChunk)->subject_index >> 8, (*pChunk)->subject_index & 0xff))->water_d = 10000.f;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ApplySplash(&temp_prev_chunk);
|
||||
}
|
||||
gDisable_advance = 0;
|
||||
|
|
@ -1995,8 +1989,7 @@ void UndoSkidAdjustment(tPipe_chunk** pChunk, tPipe_chunk* pPrev_chunk) {
|
|||
gDisable_advance = 1;
|
||||
if (pPrev_chunk == NULL) {
|
||||
HideSkid((*pChunk)->subject_index);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ApplySkidAdjustment(&pPrev_chunk);
|
||||
}
|
||||
gDisable_advance = 0;
|
||||
|
|
@ -2112,7 +2105,7 @@ tU32 FindPrevFrameTime(tU8* pPtr) {
|
|||
temp_ptr = pPtr;
|
||||
do {
|
||||
if (MoveSessionPointerBackOne(&temp_ptr)) {
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
} while (((tPipe_session*)temp_ptr)->chunk_type != ePipe_chunk_frame_boundary);
|
||||
return ((tPipe_session*)temp_ptr)->chunks.chunk_data.frame_boundary_data.time;
|
||||
|
|
@ -2317,9 +2310,9 @@ tU32 GetARStartTime() {
|
|||
|
||||
temp_ptr = gPipe_buffer_oldest;
|
||||
do {
|
||||
if (MoveSessionPointerForwardOne(&temp_ptr)) {
|
||||
return 0;
|
||||
}
|
||||
if (MoveSessionPointerForwardOne(&temp_ptr)) {
|
||||
return 0;
|
||||
}
|
||||
} while (((tPipe_session*)temp_ptr)->chunk_type != ePipe_chunk_frame_boundary);
|
||||
return ((tPipe_session*)temp_ptr)->chunks.chunk_data.frame_boundary_data.time;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "globvars.h"
|
||||
#include "globvrkm.h"
|
||||
#include "graphics.h"
|
||||
#include "harness/hooks.h"
|
||||
#include "harness/trace.h"
|
||||
#include "loading.h"
|
||||
#include "opponent.h"
|
||||
|
|
@ -874,8 +875,7 @@ void SmokeLine(int l, int x, br_scalar zbuff, int r_squared, tU8* scr_ptr, tU16*
|
|||
|
||||
for (i = 0; i < l; i++) {
|
||||
if (*depth_ptr > z) {
|
||||
offset = ((shade_offset_int - r_squared * r_multiplier_int) >> 8) &
|
||||
0xffffff00;
|
||||
offset = ((shade_offset_int - r_squared * r_multiplier_int) >> 8) & 0xffffff00;
|
||||
#if defined(DETHRACE_FIX_BUGS)
|
||||
/* Prevent buffer underflows by capping negative offsets. */
|
||||
offset = MAX(0, offset);
|
||||
|
|
@ -2051,84 +2051,92 @@ void SmudgeCar(tCar_spec* pCar, int fire_point) {
|
|||
if (gAusterity_mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
v = fire_point;
|
||||
group = 0;
|
||||
actor = pCar->car_model_actors[pCar->principal_car_actor].actor;
|
||||
model = actor->model;
|
||||
bonny = pCar->car_model_actors[pCar->car_actor_count - 1].actor;
|
||||
n = 0;
|
||||
j = 0;
|
||||
real_vertex_number = 0;
|
||||
if ((model->flags & BR_MODF_KEEP_ORIGINAL) != 0 || (model->flags & BR_MODF_UPDATEABLE) != 0) {
|
||||
BrVector3Copy(&bonny_pos, &V11MODEL(model)->groups->vertices[fire_point].p);
|
||||
point = V11MODEL(model)->groups[group].vertices[fire_point].p;
|
||||
StartPipingSession(ePipe_chunk_smudge);
|
||||
for (group = 0; group < V11MODEL(model)->ngroups; group++) {
|
||||
for (v = 0; v < V11MODEL(model)->groups[group].nvertices; v++) {
|
||||
BrVector3Sub(&tv, &V11MODEL(model)->groups[group].vertices[v].p, &bonny_pos);
|
||||
for (j = 0; j < V11MODEL(model)->groups[group].nvertices; j++) {
|
||||
BrVector3Sub(&tv, &V11MODEL(model)->groups[group].vertices[j].p, &point);
|
||||
ts = (.0144f - BrVector3LengthSquared(&tv) / SRandomBetween(.5f, 1.f)) / .0144f * 127.f;
|
||||
if (ts > 0.f) {
|
||||
ts += V11MODEL(model)->groups[group].vertex_colours[v] >> 24;
|
||||
ts += BR_ALPHA(V11MODEL(model)->groups[group].vertex_colours[j]);
|
||||
if (ts > 255.f) {
|
||||
ts = 255.f;
|
||||
}
|
||||
real_vertex_number = ts;
|
||||
if (V11MODEL(model)->groups[group].vertex_colours[v] >> 24 != real_vertex_number) {
|
||||
data[n].vertex_index = j;
|
||||
data[n].light_index = real_vertex_number - (V11MODEL(model)->groups[group].vertex_colours[v] >> 24);
|
||||
V11MODEL(model)->groups[group].vertex_colours[v] = real_vertex_number << 24;
|
||||
if (BR_ALPHA(V11MODEL(model)->groups[group].vertex_colours[j]) != (int)ts) {
|
||||
data[n].vertex_index = real_vertex_number;
|
||||
data[n].light_index = (int)ts - BR_ALPHA(V11MODEL(model)->groups[group].vertex_colours[j]);
|
||||
V11MODEL(model)->groups[group].vertex_colours[j] = (int)ts << 24;
|
||||
if ((model->flags & BR_MODF_UPDATEABLE) != 0) {
|
||||
model->vertices[V11MODEL(model)->groups[group].vertex_user[v]].index = real_vertex_number;
|
||||
model->vertices[V11MODEL(model)->groups[group].vertex_user[j]].index = (int)ts;
|
||||
}
|
||||
n += 1;
|
||||
n++;
|
||||
if (n >= COUNT_OF(data)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
j = j + 1;
|
||||
real_vertex_number++;
|
||||
}
|
||||
if (n >= COUNT_OF(data)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n != 0) {
|
||||
if (n > 0) {
|
||||
AddSmudgeToPipingSession(pCar->car_ID, pCar->principal_car_actor, n, data);
|
||||
// Added by dethrace to update gpu-buffered vertices
|
||||
model->flags |= BR_MODF_DETHRACE_FORCE_BUFFER_UPDATE;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
j = 0;
|
||||
real_vertex_number = 0;
|
||||
if (actor != bonny) {
|
||||
b_model = bonny->model;
|
||||
BrVector3Add(&tv, &actor->t.t.translate.t, &bonny_pos);
|
||||
BrVector3Sub(&tv, &tv, &bonny->t.t.translate.t);
|
||||
BrMatrix34TApplyV(&point, &tv, &bonny->t.t.mat);
|
||||
BrVector3Add(&tv, &actor->t.t.translate.t, &point);
|
||||
BrVector3Accumulate(&tv, &bonny->t.t.translate.t);
|
||||
BrMatrix34TApplyV(&bonny_pos, &tv, &bonny->t.t.mat);
|
||||
for (group = 0; group < V11MODEL(b_model)->ngroups; group++) {
|
||||
for (v = 0; v < V11MODEL(b_model)->groups[group].nvertices; v++) {
|
||||
BrVector3Sub(&tv, &V11MODEL(b_model)->groups[group].vertices[v].p, &point);
|
||||
ts = (.0144f - BrVector3LengthSquared(&tv)) / SRandomBetween(.5f, 1.f) / .0144f * 127.f;
|
||||
j = 0;
|
||||
for (j = 0; j < V11MODEL(b_model)->groups[group].nvertices; j++) {
|
||||
BrVector3Sub(&tv, &V11MODEL(b_model)->groups[group].vertices[j].p, &bonny_pos);
|
||||
ts = (.0144f - BrVector3LengthSquared(&tv) / SRandomBetween(.5f, 1.f)) / .0144f * 127.f;
|
||||
if (ts > 0.f) {
|
||||
ts += V11MODEL(b_model)->groups[group].vertex_colours[v] >> 24;
|
||||
ts += BR_ALPHA(V11MODEL(b_model)->groups[group].vertex_colours[j]);
|
||||
if (ts > 255.f) {
|
||||
ts = 255.f;
|
||||
}
|
||||
real_vertex_number = ts;
|
||||
if (V11MODEL(b_model)->groups[group].vertex_colours[v] >> 24 != real_vertex_number) {
|
||||
data[n].vertex_index = j;
|
||||
data[n].light_index = real_vertex_number - (V11MODEL(b_model)->groups[group].vertex_colours[v] >> 24);
|
||||
V11MODEL(b_model)->groups[group].vertex_colours[v] = real_vertex_number << 24;
|
||||
if (BR_ALPHA(V11MODEL(b_model)->groups[group].vertex_colours[j]) != (int)ts) {
|
||||
data[n].vertex_index = real_vertex_number;
|
||||
data[n].light_index = (int)ts - BR_ALPHA(V11MODEL(b_model)->groups[group].vertex_colours[j]);
|
||||
V11MODEL(b_model)->groups[group].vertex_colours[j] = (int)ts << 24;
|
||||
if ((b_model->flags & BR_MODF_UPDATEABLE) != 0) {
|
||||
b_model->vertices[V11MODEL(b_model)->groups[group].vertex_user[v]].index = real_vertex_number;
|
||||
b_model->vertices[V11MODEL(b_model)->groups[group].vertex_user[j]].index = (int)ts;
|
||||
}
|
||||
n += 1;
|
||||
if (n > COUNT_OF(data)) {
|
||||
n++;
|
||||
if (n >= COUNT_OF(data)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
j += 1;
|
||||
real_vertex_number++;
|
||||
}
|
||||
if (n >= COUNT_OF(data)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n != 0) {
|
||||
if (n > 0) {
|
||||
AddSmudgeToPipingSession(pCar->car_ID, pCar->car_actor_count - 1, n, data);
|
||||
|
||||
// Added by dethrace to update gpu-buffered vertices
|
||||
b_model->flags |= BR_MODF_DETHRACE_FORCE_BUFFER_UPDATE;
|
||||
}
|
||||
}
|
||||
EndPipingSession();
|
||||
|
|
|
|||
|
|
@ -381,7 +381,7 @@ void Harness_Hook_BrZbSceneRenderBegin(br_actor* world, br_actor* camera, br_pix
|
|||
}
|
||||
|
||||
void Harness_Hook_renderActor(br_actor* actor, br_model* model, br_material* material, br_token type) {
|
||||
renderer->Model(actor, model, renderer_state->state.matrix.model_to_view, type);
|
||||
renderer->Model(actor, model, material, type, renderer_state->state.matrix.model_to_view);
|
||||
}
|
||||
|
||||
void Harness_Hook_BrZbSceneRenderEnd() {
|
||||
|
|
@ -444,14 +444,6 @@ void Harness_Hook_GetMouseButtons(int* pButton1, int* pButton2) {
|
|||
IOPlatform_GetMouseButtons(pButton1, pButton2);
|
||||
}
|
||||
|
||||
// Sound hooks
|
||||
void Harness_Hook_S3Service(int unk1, int unk2) {
|
||||
Sound_Service();
|
||||
}
|
||||
|
||||
void Harness_Hook_S3StopAllOutletSounds() {
|
||||
}
|
||||
|
||||
// Filesystem hooks
|
||||
FILE* Harness_Hook_fopen(const char* pathname, const char* mode) {
|
||||
return OS_fopen(pathname, mode);
|
||||
|
|
|
|||
|
|
@ -41,19 +41,31 @@ static br_pixelmap* current_shade_table;
|
|||
// If the counters are equal, we can avoid re-uploading the same thing.
|
||||
static unsigned int flush_counter = 0, colourbuffer_upload_counter = 0;
|
||||
|
||||
typedef struct gl_vertex {
|
||||
br_vector3 p;
|
||||
br_vector2 map;
|
||||
br_vector3 n;
|
||||
float colour_index; // float to allow interpolation
|
||||
} gl_vertex;
|
||||
|
||||
struct {
|
||||
GLuint texture_pixelmap;
|
||||
GLuint uv_transform;
|
||||
GLuint shade_table;
|
||||
GLuint blend_table;
|
||||
GLuint blend_enabled;
|
||||
GLuint colour_buffer_texture;
|
||||
GLuint model, view, projection;
|
||||
GLuint palette_index_override;
|
||||
GLuint clip_plane_count;
|
||||
GLuint clip_planes[6];
|
||||
GLuint light_value;
|
||||
GLuint colour_buffer_texture;
|
||||
GLuint viewport_height;
|
||||
|
||||
GLuint material_flags;
|
||||
GLuint material_texture_enabled;
|
||||
GLuint material_texture_pixelmap;
|
||||
GLuint material_uv_transform;
|
||||
GLuint material_shade_table;
|
||||
GLuint material_blend_enabled;
|
||||
GLuint material_blend_table;
|
||||
GLuint material_index_base;
|
||||
GLuint material_index_range;
|
||||
GLuint material_shade_table_height;
|
||||
|
||||
} uniforms_3d;
|
||||
|
||||
struct {
|
||||
|
|
@ -130,23 +142,29 @@ void LoadShaders() {
|
|||
sprintf(name, "u_clip_planes[%d]", i);
|
||||
uniforms_3d.clip_planes[i] = GetValidatedUniformLocation(shader_program_3d, name);
|
||||
}
|
||||
|
||||
uniforms_3d.model = GetValidatedUniformLocation(shader_program_3d, "u_model");
|
||||
uniforms_3d.texture_pixelmap = GetValidatedUniformLocation(shader_program_3d, "u_texture_pixelmap");
|
||||
uniforms_3d.uv_transform = GetValidatedUniformLocation(shader_program_3d, "u_texture_coords_transform");
|
||||
uniforms_3d.shade_table = GetValidatedUniformLocation(shader_program_3d, "u_shade_table");
|
||||
uniforms_3d.blend_table = GetValidatedUniformLocation(shader_program_3d, "u_blend_table");
|
||||
uniforms_3d.blend_enabled = GetValidatedUniformLocation(shader_program_3d, "u_blend_enabled");
|
||||
uniforms_3d.colour_buffer_texture = GetValidatedUniformLocation(shader_program_3d, "u_colour_buffer");
|
||||
uniforms_3d.projection = GetValidatedUniformLocation(shader_program_3d, "u_projection");
|
||||
uniforms_3d.palette_index_override = GetValidatedUniformLocation(shader_program_3d, "u_palette_index_override");
|
||||
uniforms_3d.view = GetValidatedUniformLocation(shader_program_3d, "u_view");
|
||||
uniforms_3d.light_value = GetValidatedUniformLocation(shader_program_3d, "u_light_value");
|
||||
uniforms_3d.viewport_height = GetValidatedUniformLocation(shader_program_3d, "u_viewport_height");
|
||||
|
||||
uniforms_3d.material_flags = GetValidatedUniformLocation(shader_program_3d, "u_material_flags");
|
||||
uniforms_3d.material_texture_enabled = GetValidatedUniformLocation(shader_program_3d, "u_material_texture_enabled");
|
||||
uniforms_3d.material_texture_pixelmap = GetValidatedUniformLocation(shader_program_3d, "u_material_texture_pixelmap");
|
||||
uniforms_3d.material_uv_transform = GetValidatedUniformLocation(shader_program_3d, "u_material_uv_transform");
|
||||
uniforms_3d.material_shade_table = GetValidatedUniformLocation(shader_program_3d, "u_material_shade_table");
|
||||
uniforms_3d.material_shade_table_height = GetValidatedUniformLocation(shader_program_3d, "u_material_shade_table_height");
|
||||
uniforms_3d.material_blend_enabled = GetValidatedUniformLocation(shader_program_3d, "u_material_blend_enabled");
|
||||
uniforms_3d.material_blend_table = GetValidatedUniformLocation(shader_program_3d, "u_material_blend_table");
|
||||
uniforms_3d.material_index_base = GetValidatedUniformLocation(shader_program_3d, "u_material_index_base");
|
||||
uniforms_3d.material_index_range = GetValidatedUniformLocation(shader_program_3d, "u_material_index_range");
|
||||
|
||||
// bind the uniform samplers to texture units
|
||||
glUniform1i(uniforms_3d.texture_pixelmap, 0);
|
||||
glUniform1i(uniforms_3d.shade_table, 2);
|
||||
glUniform1i(uniforms_3d.blend_table, 3);
|
||||
glUniform1i(uniforms_3d.material_texture_pixelmap, 0);
|
||||
// palette occupies texture unit 1 but not required during 3d rendering
|
||||
glUniform1i(uniforms_3d.material_shade_table, 2);
|
||||
glUniform1i(uniforms_3d.material_blend_table, 3);
|
||||
glUniform1i(uniforms_3d.colour_buffer_texture, 4);
|
||||
}
|
||||
|
||||
|
|
@ -347,7 +365,7 @@ void GLRenderer_BeginScene(br_actor* camera, br_pixelmap* colour_buffer, br_pixe
|
|||
last_depth_buffer = depth_buffer;
|
||||
glViewport(colour_buffer->base_x, render_height - colour_buffer->height - colour_buffer->base_y, colour_buffer->width, colour_buffer->height);
|
||||
glUseProgram(shader_program_3d);
|
||||
glUniform1i(uniforms_3d.viewport_height, render_height);
|
||||
glUniform1ui(uniforms_3d.viewport_height, render_height);
|
||||
|
||||
current_material = NULL;
|
||||
current_shade_table = NULL;
|
||||
|
|
@ -470,7 +488,7 @@ void GLRenderer_BufferModel(br_model* model) {
|
|||
}
|
||||
}
|
||||
|
||||
fmt_vertex* verts = malloc(sizeof(fmt_vertex) * total_verts);
|
||||
gl_vertex* verts = malloc(sizeof(gl_vertex) * total_verts);
|
||||
unsigned int* indices = malloc(sizeof(int) * 3 * total_faces);
|
||||
|
||||
int v_index = 0;
|
||||
|
|
@ -482,6 +500,7 @@ void GLRenderer_BufferModel(br_model* model) {
|
|||
verts[v_index].p = v->p;
|
||||
verts[v_index].n = v->n;
|
||||
verts[v_index].map = v->map;
|
||||
verts[v_index].colour_index = BR_ALPHA(v11->groups[g].vertex_colours[i]);
|
||||
v_index++;
|
||||
}
|
||||
for (int i = 0; i < v11->groups[g].nfaces; i++) {
|
||||
|
|
@ -500,13 +519,19 @@ void GLRenderer_BufferModel(br_model* model) {
|
|||
// Vertices
|
||||
glBindVertexArray(ctx->vao_id);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ctx->vbo_id);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(fmt_vertex) * total_verts, verts, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(fmt_vertex), (void*)offsetof(fmt_vertex, p));
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(gl_vertex) * total_verts, verts, GL_STATIC_DRAW);
|
||||
// pos
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(gl_vertex), (void*)offsetof(gl_vertex, p));
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(fmt_vertex), (void*)offsetof(fmt_vertex, n));
|
||||
// normal
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(gl_vertex), (void*)offsetof(gl_vertex, n));
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(fmt_vertex), (void*)offsetof(fmt_vertex, map));
|
||||
// uv coordinates
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(gl_vertex), (void*)offsetof(gl_vertex, map));
|
||||
glEnableVertexAttribArray(2);
|
||||
// color
|
||||
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(gl_vertex), (void*)offsetof(gl_vertex, colour_index));
|
||||
glEnableVertexAttribArray(3);
|
||||
|
||||
// Indices
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ctx->ebo_id);
|
||||
|
|
@ -526,28 +551,39 @@ void setActiveMaterial(tStored_material* material) {
|
|||
return;
|
||||
}
|
||||
|
||||
glUniformMatrix2x3fv(uniforms_3d.uv_transform, 1, GL_TRUE, &material->map_transform.m[0][0]);
|
||||
glUniform1i(uniforms_3d.palette_index_override, material->index_base);
|
||||
glUniformMatrix2x3fv(uniforms_3d.material_uv_transform, 1, GL_TRUE, &material->map_transform.m[0][0]);
|
||||
|
||||
if (material->pixelmap) {
|
||||
tStored_pixelmap* stored_px = material->pixelmap->stored;
|
||||
if (stored_px == NULL) {
|
||||
LOG_PANIC("stored_px is null for pixelmap %s", material->pixelmap->identifier);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, stored_px->id);
|
||||
glUniform1ui(uniforms_3d.material_texture_enabled, 1);
|
||||
} else {
|
||||
glUniform1ui(uniforms_3d.material_texture_enabled, 0);
|
||||
|
||||
// index_base and index_range are only used for untextured materials
|
||||
glUniform1ui(uniforms_3d.material_index_base, material->index_base);
|
||||
glUniform1ui(uniforms_3d.material_index_range, material->index_range);
|
||||
}
|
||||
|
||||
if (material->shade_table) {
|
||||
glUniform1ui(uniforms_3d.material_shade_table_height, material->shade_table->height);
|
||||
GLRenderer_SetShadeTable(material->shade_table);
|
||||
}
|
||||
|
||||
if (material->index_blend) {
|
||||
glUniform1i(uniforms_3d.blend_enabled, 1);
|
||||
glUniform1ui(uniforms_3d.material_blend_enabled, 1);
|
||||
GLRenderer_SetBlendTable(material->index_blend);
|
||||
// materials with index_blend do not write to depth buffer (https://www.cwaboard.co.uk/viewtopic.php?p=105846&sid=58ad8910238000ca14b01dad85117175#p105846)
|
||||
glDepthMask(GL_FALSE);
|
||||
} else {
|
||||
glUniform1i(uniforms_3d.blend_enabled, 0);
|
||||
glUniform1ui(uniforms_3d.material_blend_enabled, 0);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
if ((material->flags & BR_MATF_LIGHT) && !(material->flags & BR_MATF_PRELIT) && material->shade_table) {
|
||||
// TODO: light value shouldn't always be 0? Works for shadows, not sure about other things.
|
||||
glUniform1i(uniforms_3d.light_value, 0);
|
||||
} else {
|
||||
glUniform1i(uniforms_3d.light_value, -1);
|
||||
}
|
||||
glUniform1ui(uniforms_3d.material_flags, material->flags);
|
||||
|
||||
if (material->flags & (BR_MATF_TWO_SIDED | BR_MATF_ALWAYS_VISIBLE)) {
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
|
@ -555,21 +591,26 @@ void setActiveMaterial(tStored_material* material) {
|
|||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
if (material->pixelmap) {
|
||||
tStored_pixelmap* stored_px = material->pixelmap->stored;
|
||||
if (stored_px != NULL) {
|
||||
glBindTexture(GL_TEXTURE_2D, stored_px->id);
|
||||
glUniform1i(uniforms_3d.palette_index_override, -1);
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR("GLRenderer_RenderModelxx");
|
||||
}
|
||||
|
||||
void GLRenderer_Model(br_actor* actor, br_model* model, br_matrix34 model_matrix, br_token render_type) {
|
||||
void GLRenderer_Model(br_actor* actor, br_model* model, br_material* material, br_token render_type, br_matrix34 model_matrix) {
|
||||
tStored_model_context* ctx;
|
||||
v11group* group;
|
||||
int element_index = 0;
|
||||
|
||||
if (model->flags & BR_MODF_DETHRACE_FORCE_BUFFER_UPDATE) {
|
||||
if (model->stored) {
|
||||
((br_object*)model->stored)->dispatch->_free((br_object*)model->stored);
|
||||
model->stored = NULL;
|
||||
}
|
||||
GLRenderer_BufferModel(model);
|
||||
model->flags &= ~BR_MODF_DETHRACE_FORCE_BUFFER_UPDATE;
|
||||
}
|
||||
|
||||
ctx = model->stored;
|
||||
v11model* v11 = model->prepared;
|
||||
|
||||
// LOG_DEBUG("model rendering %s", model->identifier);
|
||||
if (v11 == NULL) {
|
||||
// LOG_WARN("No model prepared for %s", model->identifier);
|
||||
return;
|
||||
|
|
@ -586,15 +627,8 @@ void GLRenderer_Model(br_actor* actor, br_model* model, br_matrix34 model_matrix
|
|||
glBindVertexArray(ctx->vao_id);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ctx->ebo_id);
|
||||
|
||||
// br_actor can have a material too, which is applied to the faces if the face doesn't have a texture
|
||||
if (actor->material) {
|
||||
setActiveMaterial(actor->material->stored);
|
||||
} else {
|
||||
// TODO: set defaults for now. This fixes missing curb materials but probably isn't the right fix.
|
||||
LOG_WARN_ONCE("set default palette override for missing actor material")
|
||||
glUniform1i(uniforms_3d.palette_index_override, 227);
|
||||
glUniform1i(uniforms_3d.light_value, -1);
|
||||
}
|
||||
// set default material for this actor/model
|
||||
setActiveMaterial(material->stored);
|
||||
|
||||
switch (render_type) {
|
||||
case BRT_TRIANGLE:
|
||||
|
|
@ -602,15 +636,13 @@ void GLRenderer_Model(br_actor* actor, br_model* model, br_matrix34 model_matrix
|
|||
break;
|
||||
case BRT_LINE:
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
glUniform1i(uniforms_3d.palette_index_override, 255);
|
||||
glUniform1i(uniforms_3d.light_value, -1);
|
||||
glUniform1ui(uniforms_3d.material_index_base, 255);
|
||||
glUniform1ui(uniforms_3d.material_flags, 0);
|
||||
break;
|
||||
default:
|
||||
LOG_PANIC("render_type %d is not supported?!", render_type);
|
||||
}
|
||||
|
||||
v11group* group;
|
||||
int element_index = 0;
|
||||
for (int g = 0; g < v11->ngroups; g++) {
|
||||
group = &v11->groups[g];
|
||||
setActiveMaterial(group->stored);
|
||||
|
|
@ -639,6 +671,7 @@ void GLRenderer_BufferMaterial(br_material* mat) {
|
|||
stored->flags = mat->flags;
|
||||
stored->shade_table = mat->index_shade;
|
||||
stored->index_base = mat->index_base;
|
||||
stored->index_range = mat->index_range;
|
||||
stored->index_blend = mat->index_blend;
|
||||
}
|
||||
|
||||
|
|
@ -705,7 +738,8 @@ void GLRenderer_FlushBuffers(tRenderer_flush_type flush_type) {
|
|||
for (int y = 0; y < last_colour_buffer->height; y++) {
|
||||
dest_y--;
|
||||
for (int x = 0; x < last_colour_buffer->width; x++) {
|
||||
depth_pixels[dest_y * render_width + x] = depth_buffer_flip_pixels[src_y * render_width + last_colour_buffer->base_x + x];
|
||||
uint16_t new_depth = depth_buffer_flip_pixels[src_y * render_width + last_colour_buffer->base_x + x];
|
||||
depth_pixels[dest_y * render_width + x] = new_depth;
|
||||
}
|
||||
src_y++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ void GLRenderer_SetPalette(uint8_t* rgba_colors);
|
|||
void GLRenderer_BeginScene(br_actor* camera, br_pixelmap* colour_buffer, br_pixelmap* depth_buffer);
|
||||
void GLRenderer_EndScene();
|
||||
void GLRenderer_FullScreenQuad(uint8_t* screen_buffer);
|
||||
void GLRenderer_Model(br_actor* actor, br_model* model, br_matrix34 model_matrix, br_token render_type);
|
||||
void GLRenderer_Model(br_actor* actor, br_model* model, br_material* material, br_token render_type, br_matrix34 model_matrix);
|
||||
void GLRenderer_BufferTexture(br_pixelmap* pm);
|
||||
void GLRenderer_BufferMaterial(br_material* mat);
|
||||
void GLRenderer_BufferModel(br_model* model);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ typedef struct tStored_pixelmap {
|
|||
|
||||
typedef struct tStored_material {
|
||||
int index_base;
|
||||
int index_range;
|
||||
br_uint_32 flags;
|
||||
br_pixelmap* shade_table;
|
||||
br_pixelmap* pixelmap;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ void Null_BeginFrame(br_actor* camera, br_pixelmap* colour_buffer, br_pixelmap*
|
|||
void Null_EndFrame() {}
|
||||
void Null_SetPalette(uint8_t* palette) {}
|
||||
void Null_RenderFullScreenQuad(uint8_t* src) {}
|
||||
void Null_RenderModel(br_actor* actor, br_model* model, br_matrix34 model_matrix, br_token render_type) {}
|
||||
void Null_RenderModel(br_actor* actor, br_model* model, br_material* material, br_token render_type, br_matrix34 model_matrix) {}
|
||||
void Null_RenderFrameBuffer() {}
|
||||
void Null_ClearBuffers() {}
|
||||
void Null_BufferTexture(br_pixelmap* pm) {}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ typedef struct tRenderer {
|
|||
void (*EndScene)();
|
||||
void (*SetPalette)(uint8_t* palette);
|
||||
void (*FullScreenQuad)(uint8_t* src);
|
||||
void (*Model)(br_actor* actor, br_model* model, br_matrix34 model_matrix, br_token render_type);
|
||||
void (*Model)(br_actor* actor, br_model* model, br_material* material, br_token render_type, br_matrix34 model_matrix);
|
||||
void (*ClearBuffers)();
|
||||
void (*BufferTexture)(br_pixelmap* pm);
|
||||
void (*BufferMaterial)(br_material* mat);
|
||||
|
|
|
|||
|
|
@ -1,58 +1,108 @@
|
|||
#version 140
|
||||
#extension GL_ARB_explicit_attrib_location : require
|
||||
|
||||
// Input, output variables
|
||||
// =======================
|
||||
|
||||
in vec3 v_frag_pos;
|
||||
in vec3 v_normal;
|
||||
in vec2 v_tex_coord;
|
||||
|
||||
// this is actually an integer palette index. We define it as a float to allow opengl to
|
||||
// interpolate the value across each face.
|
||||
in float v_color;
|
||||
|
||||
// 256 color mode, so each calculated color is a palette index.
|
||||
out uint out_palette_index;
|
||||
|
||||
uniform mat2x3 u_texture_coords_transform;
|
||||
uniform usampler2D u_texture_pixelmap;
|
||||
uniform usampler2D u_shade_table;
|
||||
uniform usampler2D u_blend_table;
|
||||
// Uniform variables
|
||||
// =================
|
||||
|
||||
// colour_buffer is an image which contains the current content of the framebuffer
|
||||
uniform usampler2D u_colour_buffer;
|
||||
uniform int u_palette_index_override = -1;
|
||||
uniform int u_light_value = -1;
|
||||
uniform uint u_viewport_height;
|
||||
|
||||
uniform vec4 u_clip_planes[6];
|
||||
uniform int u_clip_plane_count = 0;
|
||||
uniform int u_blend_enabled = 0;
|
||||
uniform int u_viewport_height;
|
||||
|
||||
uniform uint u_material_flags;
|
||||
uniform mat2x3 u_material_uv_transform;
|
||||
uniform usampler2D u_material_texture_pixelmap;
|
||||
uniform uint u_material_texture_enabled;
|
||||
|
||||
// material_blend_table is a 256x256 image which encodes 256 values of blending between new color and current color in framebuffer
|
||||
uniform uint u_material_blend_enabled = 0u;
|
||||
uniform usampler2D u_material_blend_table;
|
||||
|
||||
// material_shade_table is a 256px-wide image which encodes material_shade_table_height lit shades for each color
|
||||
uniform usampler2D u_material_shade_table;
|
||||
|
||||
// how many lit shades are in the material_shade_table
|
||||
uniform uint u_material_shade_table_height;
|
||||
|
||||
// For non-textured materials, defines the starting palette index
|
||||
uniform uint u_material_index_base;
|
||||
// For non-textured materials, defines the range of lit shades
|
||||
uniform uint u_material_index_range;
|
||||
|
||||
// material_flags values
|
||||
const uint BR_MATF_LIGHT = 1u;
|
||||
const uint BR_MATF_PRELIT = 2u;
|
||||
|
||||
void main() {
|
||||
|
||||
for(int i = 0; i < u_clip_plane_count; i++) {
|
||||
// calculate signed plane-vertex distance
|
||||
vec4 v4 = vec4(v_frag_pos.x, v_frag_pos.y, v_frag_pos.z, 1);
|
||||
vec4 v4 = vec4(v_frag_pos.xyz, 1);
|
||||
float d = dot(u_clip_planes[i], v4);
|
||||
if (d < 0.0) discard;
|
||||
if (d < 0) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
|
||||
if (u_palette_index_override >= 0) {
|
||||
if (u_material_texture_enabled == 0u) {
|
||||
// force palette index, no texture lookup
|
||||
out_palette_index = uint(u_palette_index_override);
|
||||
} else {
|
||||
out_palette_index = u_material_index_base;
|
||||
|
||||
if ((u_material_flags & BR_MATF_LIGHT) != 0u) {
|
||||
// TODO: lighting calculations based on https://rr2000.cwaboard.co.uk/R4/BRENDER/TEBK_43.HTM#0
|
||||
uint range = u_material_index_range;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// calculate texture uv coordinates
|
||||
vec2 sample_coord = vec3(v_tex_coord.xy, 1) * u_texture_coords_transform;
|
||||
uint texel = texture(u_texture_pixelmap, sample_coord.xy).r;
|
||||
if (u_light_value >= 0) {
|
||||
// shade_table is a 256x256 image which encodes 256 lit shades for each color
|
||||
out_palette_index = texelFetch(u_shade_table, ivec2(texel, u_light_value), 0).r;
|
||||
vec2 sample_coord = vec3(v_tex_coord.xy, 1) * u_material_uv_transform;
|
||||
uint texel = texture(u_material_texture_pixelmap, sample_coord.xy).r;
|
||||
|
||||
// color 0 is always transparent
|
||||
if (texel == 0u) {
|
||||
discard;
|
||||
}
|
||||
|
||||
if ((u_material_flags & BR_MATF_LIGHT) != 0u) {
|
||||
if ((u_material_flags & BR_MATF_PRELIT) != 0u) {
|
||||
// BR_MATF_PRELIT means the light value comes from the vertex color attribute
|
||||
uint calculated_lit_value = uint(v_color) / u_material_shade_table_height;
|
||||
out_palette_index = texelFetch(u_material_shade_table, ivec2(texel, calculated_lit_value), 0).r;
|
||||
} else {
|
||||
// TODO: lighting calculations based on https://rr2000.cwaboard.co.uk/R4/BRENDER/TEBK_43.HTM#0
|
||||
uint calculated_lit_value = 0u;
|
||||
out_palette_index = texelFetch(u_material_shade_table, ivec2(texel, calculated_lit_value), 0).r;
|
||||
}
|
||||
} else {
|
||||
// no shadetable
|
||||
// no lighting
|
||||
out_palette_index = texel;
|
||||
}
|
||||
|
||||
if (u_blend_enabled == 1 && out_palette_index != 0u) {
|
||||
// blend_table is a 256x256 image which encodes 256 values of blending between texture and existing screen pixel for each color
|
||||
// u_colour_buffer is upside down from opengl perspective. We need to sample it upside down.
|
||||
uint fb_color = texelFetch(u_colour_buffer, ivec2(gl_FragCoord.x, u_viewport_height - gl_FragCoord.y), 0).r;
|
||||
uint blended_color = texelFetch(u_blend_table, ivec2(out_palette_index, fb_color), 0).r;
|
||||
out_palette_index = blended_color;
|
||||
}
|
||||
}
|
||||
// color 0 is always transparent
|
||||
|
||||
if (u_material_blend_enabled == 1u) {
|
||||
// u_colour_buffer is upside down from opengl perspective. We need to sample it upside down.
|
||||
uint current_framebuffer_color = texelFetch(u_colour_buffer, ivec2(gl_FragCoord.x, u_viewport_height - gl_FragCoord.y), 0).r;
|
||||
out_palette_index = texelFetch(u_material_blend_table, ivec2(out_palette_index, current_framebuffer_color), 0).r;
|
||||
}
|
||||
|
||||
// HACK: Pick another black color instead of palette index 0 so we can detect which pixels have been drawn this frame in FlushBuffers
|
||||
if (out_palette_index == 0u) {
|
||||
discard;
|
||||
out_palette_index = 240u;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@
|
|||
layout (location = 0) in vec3 a_pos;
|
||||
layout (location = 1) in vec3 a_normal;
|
||||
layout (location = 2) in vec2 a_uv;
|
||||
layout (location = 3) in float a_color;
|
||||
|
||||
out vec3 v_frag_pos;
|
||||
out vec3 v_normal;
|
||||
out vec2 v_tex_coord;
|
||||
out float v_color;
|
||||
|
||||
uniform mat4 u_model;
|
||||
uniform mat4 u_view;
|
||||
|
|
@ -16,5 +18,6 @@ void main() {
|
|||
v_frag_pos = vec3(u_model * vec4(a_pos, 1.0));
|
||||
v_normal = a_normal;
|
||||
v_tex_coord = a_uv;
|
||||
v_color = a_color;
|
||||
gl_Position = u_projection * u_view * vec4(v_frag_pos, 1.0);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue