Skip to content

Commit

Permalink
[rendering] Render game upside-down to optimise pixel reading order.
Browse files Browse the repository at this point in the history
  • Loading branch information
charlesbeattie authored and tkoeppe committed May 1, 2018
1 parent 9d8a490 commit 9154942
Show file tree
Hide file tree
Showing 24 changed files with 356 additions and 100 deletions.
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
1. Moved .map files into assets/maps/src and .bsp files into assets/maps/built.
Added further pre-built maps, which removes the need for the expensive
:map_assets build step.
2. Allow game to be renderered with top-left as origin instead of bottom-left.

## release-2018-02-07 February 2018 release

Expand Down
23 changes: 18 additions & 5 deletions engine/code/client/cl_scrn.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,13 +472,13 @@ SCR_DrawScreenField
This will be called twice if rendering in stereo mode
==================
*/
void SCR_DrawScreenField( stereoFrame_t stereoFrame, qboolean skipRendering ) {
void SCR_DrawScreenField( stereoFrame_t stereoFrame, renderOrigin_t renderOrigin, qboolean skipRendering ) {
qboolean uiFullscreen;

// Many skip rendering calls below are not needed for performance
// but to match any BeginFrame skips
if ( !skipRendering ) {
re.BeginFrame( stereoFrame );
re.BeginFrame( stereoFrame, renderOrigin );
}


Expand Down Expand Up @@ -578,6 +578,19 @@ void SCR_SkipRendering( qboolean value ) {
skipRendering = value;
}

static renderOrigin_t renderOrigin = RO_BOTTOM_LEFT;

/*
==================
SCR_RenderOrigin
Render origin for subsequent calls to SCR_UpdateScreen
==================
*/
void SCR_RenderOrigin( renderOrigin_t value ) {
renderOrigin = value;
}

/*
==================
SCR_UpdateScreen
Expand Down Expand Up @@ -606,10 +619,10 @@ void SCR_UpdateScreen( void ) {
int in_anaglyphMode = Cvar_VariableIntegerValue("r_anaglyphMode");
// if running in stereo, we need to draw the frame twice
if ( cls.glconfig.stereoEnabled || in_anaglyphMode) {
SCR_DrawScreenField( STEREO_LEFT, skipRendering );
SCR_DrawScreenField( STEREO_RIGHT, skipRendering );
SCR_DrawScreenField( STEREO_LEFT, renderOrigin, skipRendering );
SCR_DrawScreenField( STEREO_RIGHT, renderOrigin, skipRendering );
} else {
SCR_DrawScreenField( STEREO_CENTER, skipRendering );
SCR_DrawScreenField( STEREO_CENTER, renderOrigin, skipRendering );
}

if ( !skipRendering ) {
Expand Down
1 change: 1 addition & 0 deletions engine/code/client/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ void CL_SaveConsoleHistory( void );
//
void SCR_Init (void);
void SCR_SkipRendering (qboolean value);
void SCR_RenderOrigin (renderOrigin_t value);
void SCR_UpdateScreen (void);

void SCR_RenderCustomView (void);
Expand Down
68 changes: 36 additions & 32 deletions engine/code/deepmind/dmlab_connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,13 @@ static int dmlab_setting(void* context, const char* key, const char* value) {
static int dmlab_init(void* context) {
GameContext* gc = context;
DeepmindContext* ctx = gc->dm_ctx;
SCR_SkipRendering(!ctx->hooks.get_native_app(ctx->userdata));
if (ctx->hooks.get_native_app(ctx->userdata)) {
SCR_SkipRendering(false);
SCR_RenderOrigin(RO_BOTTOM_LEFT);
} else {
SCR_SkipRendering(true);
SCR_RenderOrigin(RO_TOP_LEFT);
}

if (gc->vm_mode != VMI_NATIVE) {
Q_strcat(gc->command_line, sizeof(gc->command_line),
Expand Down Expand Up @@ -879,6 +885,7 @@ static void dmlab_observation(

if (!gc->current_screen_rendered) {
SCR_SkipRendering(false);
SCR_RenderOrigin(RO_TOP_LEFT);
SCR_UpdateScreen();
gc->current_screen_rendered = true;
}
Expand All @@ -900,16 +907,7 @@ static void dmlab_observation(
switch (observation_idx) {
case kObservations_RgbInterlaced: {
gc->image_buffer = realloc_or_die(gc->image_buffer, window_size * 3);
unsigned char* const image_buffer = gc->image_buffer;
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
int loc = (i * width + j) * 3;
int invy = (height - i - 1) * width + j;
image_buffer[invy * 3 + 0] = temp_buffer[loc + 0];
image_buffer[invy * 3 + 1] = temp_buffer[loc + 1];
image_buffer[invy * 3 + 2] = temp_buffer[loc + 2];
}
}
memcpy(gc->image_buffer, temp_buffer, window_size * 3);
break;
}
case kObservations_RgbdInterlaced: {
Expand All @@ -918,10 +916,10 @@ static void dmlab_observation(
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
int loc = (i * width + j) * 3;
int invy = (height - i - 1) * width + j;
image_buffer[invy * 4 + 0] = temp_buffer[loc + 0];
image_buffer[invy * 4 + 1] = temp_buffer[loc + 1];
image_buffer[invy * 4 + 2] = temp_buffer[loc + 2];
int y = i * width + j;
image_buffer[y * 4 + 0] = temp_buffer[loc + 0];
image_buffer[y * 4 + 1] = temp_buffer[loc + 1];
image_buffer[y * 4 + 2] = temp_buffer[loc + 2];
}
}
break;
Expand All @@ -932,10 +930,10 @@ static void dmlab_observation(
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
int loc = (i * width + j) * 3;
int invy = (height - i - 1) * width + j;
image_buffer[invy + window_size * 0] = temp_buffer[loc + 0];
image_buffer[invy + window_size * 1] = temp_buffer[loc + 1];
image_buffer[invy + window_size * 2] = temp_buffer[loc + 2];
int y = i * width + j;
image_buffer[y + window_size * 0] = temp_buffer[loc + 0];
image_buffer[y + window_size * 1] = temp_buffer[loc + 1];
image_buffer[y + window_size * 2] = temp_buffer[loc + 2];
}
}
break;
Expand All @@ -946,10 +944,10 @@ static void dmlab_observation(
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
int loc = (i * width + j) * 3;
int invy = (height - i - 1) * width + j;
image_buffer[invy + window_size * 0] = temp_buffer[loc + 0];
image_buffer[invy + window_size * 1] = temp_buffer[loc + 1];
image_buffer[invy + window_size * 2] = temp_buffer[loc + 2];
int y = i * width + j;
image_buffer[y + window_size * 0] = temp_buffer[loc + 0];
image_buffer[y + window_size * 1] = temp_buffer[loc + 1];
image_buffer[y + window_size * 2] = temp_buffer[loc + 2];
}
}
break;
Expand All @@ -960,16 +958,16 @@ static void dmlab_observation(
if (render_depth) {
unsigned char* const image_buffer = gc->image_buffer;
temp_buffer = bind_pixel_observation(gc, kPixelBufferTypeEnum_Depth);
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
int loc = i * width + j;
int invy = (height - i - 1) * width + j;
if (observation_idx == kObservations_RgbdInterlaced) {
image_buffer[invy * 4 + 3] = temp_buffer[loc];
} else {
image_buffer[invy + window_size * 3] = temp_buffer[loc];
if (observation_idx == kObservations_RgbdInterlaced) {
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
int loc = i * width + j;
int y = i * width + j;
image_buffer[y * 4 + 3] = temp_buffer[loc];
}
}
} else {
memcpy(image_buffer + window_size * 3, temp_buffer, window_size);
}
unbind_pixel_observation(gc);
}
Expand Down Expand Up @@ -1037,7 +1035,13 @@ static EnvCApi_EnvironmentStatus dmlab_advance(
re.MakeCurrent();
GameContext* gc = context;
DeepmindContext* ctx = gc->dm_ctx;
SCR_SkipRendering(!ctx->hooks.get_native_app(ctx->userdata));
if (ctx->hooks.get_native_app(ctx->userdata)) {
SCR_SkipRendering(false);
SCR_RenderOrigin(RO_BOTTOM_LEFT);
} else {
SCR_SkipRendering(true);
SCR_RenderOrigin(RO_TOP_LEFT);
}
gc->current_screen_rendered = false;
ctx->hooks.events.clear(ctx->userdata);
*reward = 0;
Expand Down
4 changes: 3 additions & 1 deletion engine/code/renderercommon/tr_common.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc., 2017 Google Inc.
Copyright (C) 1999-2005 Id Software, Inc., 2017-2018 Google Inc.
This file is part of Quake III Arena source code.
Expand Down Expand Up @@ -119,6 +119,8 @@ extern cvar_t *r_saveFontData;

extern cvar_t *r_textureMaxSize;

extern cvar_t *r_vertFlipBuffer;

qboolean R_GetModeInfo( int *width, int *height, int *buff_width, int *buff_height, float *windowAspect, int mode );

float R_NoiseGet4f( float x, float y, float z, double t );
Expand Down
2 changes: 1 addition & 1 deletion engine/code/renderercommon/tr_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ typedef struct {
void (*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);
void (*UploadCinematic) (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);

void (*BeginFrame)( stereoFrame_t stereoFrame );
void (*BeginFrame)( stereoFrame_t stereoFrame, renderOrigin_t renderOrigin );

// if the pointers are not NULL, timing info will be returned
void (*EndFrame)( int *frontEndMsec, int *backEndMsec );
Expand Down
4 changes: 4 additions & 0 deletions engine/code/renderercommon/tr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ typedef enum {
STEREO_RIGHT
} stereoFrame_t;

typedef enum {
RO_BOTTOM_LEFT,
RO_TOP_LEFT,
} renderOrigin_t;

/*
** glconfig_t
Expand Down
51 changes: 35 additions & 16 deletions engine/code/renderergl1/tr_backend.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc., 2017 Google Inc.
Copyright (C) 1999-2005 Id Software, Inc., 2017-2018 Google Inc.
This file is part of Quake III Arena source code.
Expand Down Expand Up @@ -124,29 +124,39 @@ void GL_BindMultitexture( image_t *image0, GLuint env0, image_t *image1, GLuint
** GL_Cull
*/
void GL_Cull( int cullType ) {
if ( glState.faceCulling == cullType ) {
return;
}

glState.faceCulling = cullType;

if ( cullType == CT_TWO_SIDED )
if ( cullType == CT_TWO_SIDED )
{
qglDisable( GL_CULL_FACE );
if ( glState.faceCulling != CT_TWO_SIDED )
{
qglDisable( GL_CULL_FACE );
}
}
else
{
qboolean cullFront;
qglEnable( GL_CULL_FACE );
GLenum faceCullFront;
if ( backEnd.viewParms.isMirror != backEnd.viewParms.vertFlipBuffer )
{
faceCullFront = (cullType == CT_FRONT_SIDED) ? GL_BACK : GL_FRONT;
}
else
{
faceCullFront = (cullType == CT_FRONT_SIDED) ? GL_FRONT : GL_BACK;
}

if ( glState.faceCulling != cullType )
{
qglEnable( GL_CULL_FACE );
}

cullFront = (cullType == CT_FRONT_SIDED);
if ( backEnd.viewParms.isMirror )
if ( glState.faceCullFront != faceCullFront )
{
cullFront = !cullFront;
qglCullFace( faceCullFront );
glState.faceCullFront = faceCullFront;
}

qglCullFace( cullFront ? GL_FRONT : GL_BACK );
}

glState.faceCulling = cullType;
}

/*
Expand Down Expand Up @@ -467,6 +477,7 @@ void RB_BeginDrawingView (void) {
}

glState.faceCulling = -1; // force face culling to set next time
glState.faceCullFront = -1;

// we will only draw a sun if there was sky rendered in this view
backEnd.skyRenderedThisView = qfalse;
Expand Down Expand Up @@ -697,13 +708,21 @@ RB_SetGL2D
*/
void RB_SetGL2D (void) {
backEnd.projection2D = qtrue;
backEnd.viewParms.vertFlipBuffer = backEnd.refdef.vertFlipBuffer;

// set 2D virtual screen size
qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
qglMatrixMode(GL_PROJECTION);
qglLoadIdentity ();
qglOrtho (0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1);
if(backEnd.viewParms.vertFlipBuffer)
{
qglOrtho (0, glConfig.vidWidth, 0, glConfig.vidHeight, 0, 1);
}
else
{
qglOrtho (0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1);
}
qglMatrixMode(GL_MODELVIEW);
qglLoadIdentity ();

Expand Down
10 changes: 8 additions & 2 deletions engine/code/renderergl1/tr_cmds.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 1999-2005 Id Software, Inc., 2018 Google Inc.
This file is part of Quake III Arena source code.
Expand Down Expand Up @@ -337,6 +337,8 @@ void RE_BeginFrameCustomView( void ) {
}

tr.refdef.stereoFrame = STEREO_CENTER;

tr.refdef.vertFlipBuffer = qfalse;
}

void RE_EndFrameCustomView( void ) {
Expand All @@ -359,7 +361,7 @@ If running in stereo, RE_BeginFrame will be called twice
for each RE_EndFrame
====================
*/
void RE_BeginFrame( stereoFrame_t stereoFrame ) {
void RE_BeginFrame( stereoFrame_t stereoFrame, renderOrigin_t renderOrigin ) {
drawBufferCommand_t *cmd = NULL;
colorMaskCommand_t *colcmd = NULL;

Expand Down Expand Up @@ -523,6 +525,10 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) {
}

tr.refdef.stereoFrame = stereoFrame;

tr.refdef.vertFlipBuffer = r_vertFlipBuffer->integer >= 0 ?
r_vertFlipBuffer->integer != 0 :
renderOrigin == RO_TOP_LEFT;
}


Expand Down
16 changes: 12 additions & 4 deletions engine/code/renderergl1/tr_flares.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 1999-2005 Id Software, Inc., 2018 Google Inc.
This file is part of Quake III Arena source code.
Expand Down Expand Up @@ -520,9 +520,17 @@ void RB_RenderFlares (void) {
qglMatrixMode( GL_PROJECTION );
qglPushMatrix();
qglLoadIdentity();
qglOrtho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
-99999, 99999 );
if ( backEnd.viewParms.vertFlipBuffer ) {
qglOrtho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight, backEnd.viewParms.viewportY,
-99999, 99999 );
}
else
{
qglOrtho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
-99999, 99999 );
}

for ( f = r_activeFlares ; f ; f = f->next ) {
if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
Expand Down
Loading

0 comments on commit 9154942

Please sign in to comment.