Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmupen64plus/mupen64plus-video-z64/src/rgl.cpp
2 views
1
/*
2
* z64
3
*
4
* Copyright (C) 2007 ziggy
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
15
*
16
* You should have received a copy of the GNU General Public License along
17
* with this program; if not, write to the Free Software Foundation, Inc.,
18
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
*
20
**/
21
22
/*
23
*
24
* TODO
25
*
26
* - hires framebuffer : scale them accordingly to the GL screen resolution
27
*
28
* - multitexturing avec tilenum == 7, ca marche comment ?
29
* --> tilenum=7 should be translated to tilenum=0 for triangle and texrec primitives
30
*
31
* - CvgXAlpha mode not really correct, effect probably depends on the texture format
32
* --> apparently fixed, Intensity textures shouldn't be affected by this effect
33
* --> correction : it had nothing to do with the texture format, but with
34
* the alpha_cvg_select flag
35
*
36
* - fix fbo depth clear in LEGO racer (also affects beetle and reflection in rally 99)
37
* (also affects Zelda OOT subscreen)
38
* --> DONE
39
*
40
* - frame buffer ordering (LEGO racer)
41
* --> DONE but required also less conservative framebuffer check
42
*
43
* - format conversion for hires framebuffers when required (CBFD , Banjo)
44
* --> DONE (quick hack)
45
*
46
* - some texture (4 ? 8 bits ?) problems
47
* --> either they're fixed, either I forgot which problem it was
48
*
49
* - mirrored textures
50
* --> done but rely on a GL extension, do we care ?
51
*
52
* - better blend
53
* --> mostly done slow way, now need to implement the quick way
54
* --> done faster way, seems to work reasonably well
55
*
56
* - need to sort out combiner clamp modes
57
* --> started but not complete
58
* --> the problem is much more complicated, it's not combiner clamping
59
* but coverage calculation modes.
60
*
61
* - fog !!
62
* --> done
63
*
64
* PROBLEMS
65
*
66
* - this list needs to be updated :)
67
* - links not always rendered in the subscreen
68
* --> depth clear problem, anything else ? FIXED
69
* - texture problems in beetle
70
* --> mostly fixed, it was multitexturing, the sky still has a weird problem though
71
* --> completely fixed at last (the sky uses tex2 in the second combiner cycle,
72
* which should be interpreted as tex1 (apparently tex2 isn't available in the
73
* second cycle)
74
* UPDATE : in fact tex1 and tex2 need to be swapped in the second step of
75
* the combiner, weird but it fixes a few other problems as well
76
*
77
**/
78
79
#include "rdp.h"
80
#include "rgl.h"
81
82
#include <SDL.h>
83
84
//#define NOFBO
85
#define ZTEX
86
#define FBORGBA
87
88
rglTexCache_t rglTexCache[0x1000];
89
uint8_t rglTmpTex[1024*1024*4];
90
uint8_t rglTmpTex2[1024*1024*4];
91
92
volatile int rglStatus, rglNextStatus;
93
94
static int wireframe;
95
96
static uint32_t old_vi_origin;
97
98
int rglFrameCounter;
99
100
extern int viewportOffset;
101
rglSettings_t rglSettings;
102
103
rglDepthBuffer_t zBuffers[MAX_DEPTH_BUFFERS];
104
int nbZBuffers;
105
106
rglRenderBuffer_t rBuffers[MAX_RENDER_BUFFERS];
107
int nbRBuffers;
108
rglRenderBuffer_t * curRBuffer;
109
rglRenderBuffer_t * curZBuffer;
110
rglRenderBufferHead_t rBufferHead;
111
112
int rglTexCacheCounter = 1;
113
114
rglTexture_t rglTextures[RGL_TEX_CACHE_SIZE];
115
116
rglRenderChunk_t chunks[MAX_RENDER_CHUNKS];
117
rglRenderChunk_t * curChunk;
118
int nbChunks, renderedChunks;
119
120
rglStrip_t strips[MAX_STRIPS];
121
rglVertex_t vtxs[6*MAX_STRIPS];
122
int nbStrips, nbVtxs;
123
124
rglRenderMode_t renderModesDb[MAX_RENDER_MODES];
125
int nbRenderModes;
126
127
rglShader_t * rglCopyShader;
128
rglShader_t * rglCopyDepthShader;
129
130
int rglScreenWidth = 320, rglScreenHeight = 240;
131
132
#define CHECK_FRAMEBUFFER_STATUS() \
133
{\
134
GLenum status; \
135
status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); \
136
/*LOGERROR("%x\n", status);*/\
137
switch(status) { \
138
case GL_FRAMEBUFFER_COMPLETE_EXT: \
139
/*LOGERROR("framebuffer complete!\n");*/\
140
break; \
141
case GL_FRAMEBUFFER_UNSUPPORTED_EXT: \
142
LOGERROR("framebuffer GL_FRAMEBUFFER_UNSUPPORTED_EXT\n");\
143
/* you gotta choose different formats */ \
144
/*rglAssert(0);*/ \
145
break; \
146
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: \
147
LOGERROR("framebuffer INCOMPLETE_ATTACHMENT\n");\
148
break; \
149
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: \
150
LOGERROR("framebuffer FRAMEBUFFER_MISSING_ATTACHMENT\n");\
151
break; \
152
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: \
153
LOGERROR("framebuffer FRAMEBUFFER_DIMENSIONS\n");\
154
break; \
155
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: \
156
LOGERROR("framebuffer INCOMPLETE_FORMATS\n");\
157
break; \
158
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: \
159
LOGERROR("framebuffer INCOMPLETE_DRAW_BUFFER\n");\
160
break; \
161
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: \
162
LOGERROR("framebuffer INCOMPLETE_READ_BUFFER\n");\
163
break; \
164
case GL_FRAMEBUFFER_BINDING_EXT: \
165
LOGERROR("framebuffer BINDING_EXT\n");\
166
break; \
167
default: \
168
LOGERROR("framebuffer generic error\n");\
169
break; \
170
/* programming error; will fail on all hardware */ \
171
/*rglAssert(0);*/ \
172
}\
173
}
174
/*
175
case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: \
176
LOGERROR("framebuffer INCOMPLETE_DUPLICATE_ATTACHMENT\n");\
177
break; \
178
*/
179
180
rglDepthBuffer_t * rglFindDepthBuffer(uint32_t address, int width, int height)
181
{
182
int i;
183
rglDepthBuffer_t * buffer;
184
for (i=0; i<nbZBuffers; i++)
185
if (zBuffers[i].address == address &&
186
zBuffers[i].width == width &&
187
zBuffers[i].height == height)
188
return zBuffers+i;
189
190
rglAssert(nbZBuffers < MAX_DEPTH_BUFFERS);
191
buffer = zBuffers + nbZBuffers++;
192
193
LOG("Creating depth buffer %x %d x %d\n", address, width, height);
194
195
buffer->address = address;
196
buffer->width = width;
197
buffer->height = height;
198
199
// glGenRenderbuffersEXT(1, &buffer->zbid);
200
// glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buffer->zbid);
201
// rglAssert(glGetError() == GL_NO_ERROR);
202
// glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,
203
// buffer->width, buffer->height);
204
// rglAssert(glGetError() == GL_NO_ERROR);
205
206
#ifdef ZTEX
207
glGenTextures(1, &buffer->zbid);
208
rglAssert(glGetError() == GL_NO_ERROR);
209
glBindTexture(GL_TEXTURE_2D, buffer->zbid);
210
rglAssert(glGetError() == GL_NO_ERROR);
211
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
212
buffer->width, buffer->height, 0,
213
GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
214
rglAssert(glGetError() == GL_NO_ERROR);
215
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
216
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
217
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
218
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
219
glBindTexture(GL_TEXTURE_2D, 0);
220
#else
221
glGenRenderbuffersEXT(1, &buffer->zbid);
222
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buffer->zbid);
223
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,
224
buffer->width, buffer->height);
225
226
#endif
227
228
return buffer;
229
}
230
231
void rglDeleteRenderBuffer(rglRenderBuffer_t & buffer)
232
{
233
buffer.mod.xl = buffer.mod.yl = 0;
234
buffer.mod.xh = buffer.mod.yh = 8192;
235
buffer.depthBuffer = 0;
236
#ifndef NOFBO
237
if (buffer.fbid) {
238
glDeleteFramebuffersEXT(1, &buffer.fbid);
239
buffer.fbid = 0;
240
}
241
if (buffer.texid) {
242
glDeleteTextures(1, &buffer.texid);
243
buffer.texid = 0;
244
}
245
buffer.nbDepthSections = 0;
246
#ifdef RGL_EXACT_BLEND
247
glDeleteFramebuffersEXT(1, &buffer.fbid2);
248
buffer.fbid2 = 0;
249
glDeleteTextures(1, &buffer.texid2);
250
buffer.texid2 = 0;
251
#endif
252
#endif
253
}
254
255
void rglFullSync()
256
{
257
if (rglSettings.forceSwap)
258
// hack for starwars, perfect dark subscreen to prevent filling up our chunk table
259
old_vi_origin = ~0;
260
}
261
262
// note : if "same" is 1 then both tiles use the same texture, in this
263
// case we can't safely modify the clamping mode
264
void rglFixupMapping(rglStrip_t & strip, rglTile_t & tile,
265
float ds, float dt, float ss, float st,
266
float & dsm, float & dtm, int same)
267
{
268
float mins = strip.vtxs[0].s;
269
float mint = strip.vtxs[0].t;
270
int i;
271
if ( (tile.mask_s && !tile.cs) || (tile.mask_t && !tile.ct) )
272
for (i=1; i<strip.nbVtxs; i++) {
273
if (strip.vtxs[i].s < mins)
274
mins = strip.vtxs[i].s;
275
if (strip.vtxs[i].t < mint)
276
mint = strip.vtxs[i].t;
277
}
278
if (tile.mask_s && !tile.cs)
279
dsm = -((int(mins+0.5f - tile.sl*float(1<<(tile.shift_s+4))/64.0f) + (tile.ms<<tile.mask_s)) & ((~tile.ms)<<(tile.mask_s+tile.shift_s+4)>>4));
280
else
281
dsm = 0;
282
if (tile.mask_t && !tile.ct)
283
dtm = -((int(mint+0.5f - tile.tl*float(1<<(tile.shift_t+4))/64.0f) + (tile.mt<<tile.mask_t)) & ((~tile.mt)<<(tile.mask_t+tile.shift_t+4)>>4));
284
else
285
dtm = 0;
286
287
if (rglSettings.hiresFb && tile.hiresBuffer)
288
return;
289
else {
290
GLuint wws = tile.ws, wwt = tile.wt;
291
292
if (same || wws != GL_REPEAT)
293
goto skips;
294
for (i=0; i<strip.nbVtxs; i++) {
295
float a = (strip.vtxs[i].s + ds + dsm);
296
if ((a-0.5f)/ss > 1 || (a+0.5f)/ss < 0) {
297
goto skips;
298
}
299
}
300
//LOG("fixing S clamp\n");
301
wws = GL_CLAMP_TO_EDGE;
302
skips:
303
if (tile.tex->ws != wws) {
304
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wws);
305
tile.tex->ws = wws;
306
}
307
308
if (same || wwt != GL_REPEAT)
309
goto skipt;
310
for (i=0; i<strip.nbVtxs; i++) {
311
float a = (strip.vtxs[i].t + dt + dtm);
312
if ((a-0.5f)/st > 1 || (a+0.5f)/st < 0)
313
goto skipt;
314
}
315
//LOG("fixing T clamp\n");
316
wwt = GL_CLAMP_TO_EDGE;
317
skipt:
318
if (tile.tex->wt != wwt) {
319
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wwt);
320
tile.tex->wt = wwt;
321
}
322
}
323
}
324
325
int rglUseTile(rglTile_t & tile, float & ds, float & dt, float & ss, float & st)
326
{
327
int res = 0;
328
ds = -tile.sl*float(1<<(tile.shift_s+4))/64.0f;
329
dt = -tile.tl*float(1<<(tile.shift_t+4))/64.0f;
330
if (rglSettings.hiresFb && tile.hiresBuffer) {
331
rglRenderBuffer_t & hbuf = *tile.hiresBuffer;
332
// if (hbuf.flags & RGL_RB_DEPTH) {
333
// glBindTexture(GL_TEXTURE_2D, hbuf.depthBuffer->zbid);
334
// res = RGL_COMB_IN0_DEPTH;
335
// } else
336
glBindTexture(GL_TEXTURE_2D, hbuf.texid);
337
rglAssert(glGetError() == GL_NO_ERROR);
338
ss = -(hbuf.width<<(tile.shift_s+4)>>4);
339
st = -(hbuf.height<<(tile.shift_t+4)>>4);
340
ds = -ds - (((int32_t(tile.hiresAddress) - int32_t(hbuf.addressStart)) % hbuf.line) >> hbuf.size << 1);
341
dt = -dt - (int32_t(tile.hiresAddress) - int32_t(hbuf.addressStart)) / hbuf.line;
342
ss /= float(hbuf.realWidth)/hbuf.fboWidth;
343
st /= float(hbuf.realHeight)/hbuf.fboHeight;
344
ds = ss - ds;
345
dt = st - dt;
346
347
DUMP("texture fb %p shift %g x %g (scale %g x %g) tile %d x %d (sl %d tl %d)\n",
348
&hbuf, ds, dt, ss, st, tile.w, tile.h,
349
tile.sl, tile.tl);
350
} else {
351
glBindTexture(GL_TEXTURE_2D, tile.tex->id);
352
rglAssert(glGetError() == GL_NO_ERROR);
353
ss = tile.w<<(tile.shift_s+4)>>4; st = tile.h<<(tile.shift_t+4)>>4;
354
355
if (tile.tex->filter != tile.filter) {
356
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tile.filter);
357
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tile.filter);
358
rglAssert(glGetError() == GL_NO_ERROR);
359
tile.tex->filter = tile.filter;
360
}
361
}
362
return res;
363
}
364
365
void rglPrepareFramebuffer(rglRenderBuffer_t & buffer)
366
{
367
//int olderased = buffer.flags & RGL_RB_ERASED;
368
369
if (buffer.area.xh == 8192)
370
return;
371
372
GLuint restoreId = 0, restoreFbid = 0;
373
float d2 = -1;
374
float d = 0;
375
float restoreW = buffer.width+d2, restoreH = buffer.height+d2;
376
int w, h;
377
restoreW *= float(buffer.fboWidth+d) / (buffer.realWidth+d);
378
restoreH *= float(buffer.fboHeight+d) / (buffer.realHeight+d);
379
380
buffer.flags &= ~RGL_RB_ERASED;
381
382
// buffer.width = ((buffer.area.xl - buffer.area.xh >>2) + 15)&~15;
383
// buffer.height = ((buffer.area.yl - buffer.area.yh >>2) + 15)&~15;
384
// buffer.width = ((buffer.area.xl >>2) + 3)&~3;
385
// buffer.height = ((buffer.area.yl >>2) + 3)&~3;
386
//buffer.width = ((buffer.area.xl >>2))&~7;
387
buffer.width = buffer.fbWidth;
388
//buffer.height = ((buffer.area.yl >>2))&~7;
389
buffer.height = ((buffer.area.yl >>2));
390
if (!buffer.width) buffer.width = 1;
391
if (!buffer.height) buffer.height = 1;
392
393
buffer.addressStop = buffer.addressStart + buffer.line * ((buffer.area.yl >>2)+1);
394
395
if (rglSettings.lowres) {
396
buffer.realWidth = buffer.width;
397
buffer.realHeight = buffer.height;
398
} else {
399
if (buffer.width <= 128 || buffer.height <= 128) {
400
buffer.realWidth = buffer.width*4;
401
buffer.realHeight = buffer.height*4;
402
buffer.flags &= ~RGL_RB_FULL;
403
} else {
404
buffer.realWidth = screen_width * buffer.width / rglScreenWidth;
405
buffer.realHeight = screen_height * buffer.height / rglScreenHeight;
406
// buffer.realWidth = screen_width * buffer.width / vi_width;
407
// if (buffer.height > 250)
408
// buffer.realHeight = screen_height * buffer.height / 480;
409
// else
410
// buffer.realHeight = screen_height * buffer.height / 240;
411
buffer.flags |= RGL_RB_FULL;
412
}
413
}
414
415
if (rglSettings.noNpotFbos) {
416
w = 1; h = 1;
417
while (w < buffer.realWidth) w <<= 1;
418
while (h < buffer.realHeight) h <<= 1;
419
} else {
420
w = buffer.realWidth;
421
h = buffer.realHeight;
422
}
423
424
#ifndef NOFBO
425
if (buffer.fboWidth == w && buffer.fboHeight == h)
426
buffer.redimensionStamp = rglFrameCounter;
427
428
if (buffer.fbid &&
429
(//buffer.fboWidth < w || buffer.fboHeight < h ||
430
(rglFrameCounter - buffer.redimensionStamp > 4))) {
431
LOG("Redimensionning buffer\n");
432
restoreId = buffer.texid;
433
restoreFbid = buffer.fbid;
434
buffer.texid = buffer.fbid = 0;
435
rglDeleteRenderBuffer(buffer);
436
}
437
438
DUMP("Render buffer %p at %x --> %x\n", &buffer,
439
buffer.addressStart, buffer.addressStop);
440
441
if (!buffer.fbid) {
442
int glfmt;
443
switch (buffer.format) {
444
// case RDP_FORMAT_I:
445
// case RDP_FORMAT_CI:
446
// glfmt = GL_LUMINANCE;
447
// break;
448
default:
449
#ifdef FBORGBA
450
glfmt = GL_RGBA;
451
#else
452
glfmt = GL_RGB;
453
#endif
454
}
455
456
LOG("creating fbo %x %dx%d (%dx%d) fmt %x\n", buffer.addressStart, buffer.width, buffer.height, w, h, buffer.format);
457
458
buffer.fboWidth = w;
459
buffer.fboHeight = h;
460
461
#ifdef RGL_EXACT_BLEND
462
glGenFramebuffersEXT(1, &buffer.fbid2);
463
rglAssert(glGetError() == GL_NO_ERROR);
464
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid2);
465
466
// FIXME we should not need to allocate a color texture for depth only rendering
467
if (1||!(buffer.flags & RGL_RB_DEPTH)) {
468
glGenTextures(1, &buffer.texid2);
469
rglAssert(glGetError() == GL_NO_ERROR);
470
glBindTexture(GL_TEXTURE_2D, buffer.texid2);
471
rglAssert(glGetError() == GL_NO_ERROR);
472
glTexImage2D(GL_TEXTURE_2D, 0, glfmt, w, h, 0,
473
glfmt, GL_UNSIGNED_BYTE, NULL);
474
rglAssert(glGetError() == GL_NO_ERROR);
475
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
476
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
477
478
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
479
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
480
481
rglAssert(glGetError() == GL_NO_ERROR);
482
glBindTexture(GL_TEXTURE_2D, 0);
483
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
484
GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,
485
buffer.texid2, 0);
486
}
487
#endif
488
489
if (restoreId) {
490
buffer.fbid = restoreFbid;
491
} else {
492
glGenFramebuffersEXT(1, &buffer.fbid);
493
rglAssert(glGetError() == GL_NO_ERROR);
494
}
495
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid);
496
497
// FIXME we should not need to allocate a color texture for depth only rendering
498
if (1||!(buffer.flags & RGL_RB_DEPTH)) {
499
glGenTextures(1, &buffer.texid);
500
rglAssert(glGetError() == GL_NO_ERROR);
501
glBindTexture(GL_TEXTURE_2D, buffer.texid);
502
rglAssert(glGetError() == GL_NO_ERROR);
503
glTexImage2D(GL_TEXTURE_2D, 0, glfmt, w, h, 0,
504
glfmt, GL_UNSIGNED_BYTE, NULL);
505
rglAssert(glGetError() == GL_NO_ERROR);
506
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
507
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
508
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
509
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
510
511
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
512
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
513
514
rglAssert(glGetError() == GL_NO_ERROR);
515
glBindTexture(GL_TEXTURE_2D, 0);
516
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
517
GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,
518
buffer.texid, 0);
519
520
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0 );
521
522
if (!restoreId) {
523
glClearColor(0, 0, 0, 1);
524
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
525
glClear(GL_COLOR_BUFFER_BIT);
526
} else {
527
glViewport(0, 0, buffer.realWidth, buffer.realHeight);
528
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
529
glDisable(GL_DEPTH_TEST);
530
glBindTexture(GL_TEXTURE_2D, restoreId);
531
rglUseShader(rglCopyShader);
532
glBegin(GL_TRIANGLE_STRIP);
533
glTexCoord2f((buffer.width+d2)/restoreW, 0); glVertex2f(1, 0);
534
glTexCoord2f(0, 0); glVertex2f(0, 0);
535
glTexCoord2f((buffer.width+d2)/restoreW, (buffer.height+d2)/restoreH); glVertex2f(1, 1);
536
glTexCoord2f(0, (buffer.height+d2)/restoreH); glVertex2f(0, 1);
537
glEnd();
538
glDeleteTextures(1, &restoreId);
539
}
540
}
541
} else
542
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid);
543
#endif
544
545
rglAssert(glGetError() == GL_NO_ERROR);
546
547
// hack for LEGO racer, real fix coming soon
548
// if (olderased)
549
// {
550
// glDepthMask(GL_TRUE);
551
// glClearDepth(1);
552
// glClear(GL_DEPTH_BUFFER_BIT);
553
// }
554
}
555
556
void rglRenderChunks(rglRenderBuffer_t * upto)
557
{
558
if (upto->area.xh != 8192 && renderedChunks < upto->chunkId)
559
rglRenderChunks(upto->chunkId);
560
}
561
562
void rglRenderChunks(int upto)
563
{
564
int i;
565
//printf("vi_origin %x nbChunks %d\n", vi_origin, nbChunks);
566
rglRenderBuffer_t * lastBuffer = 0;
567
uint32_t lastDepthAddress = ~0;
568
float zb = 0.0f;
569
570
DUMP("rendering chunks upto %d / %d\n", upto, nbChunks);
571
572
glEnable(GL_SCISSOR_TEST);
573
for (i=renderedChunks; i<upto; i++) {
574
int j;
575
rglRenderChunk_t & chunk = chunks[i];
576
577
if (chunk.renderBuffer->nbDepthSections) {
578
// reselect the renderbuffer with correct width (needed by LEGO racer,
579
// because they clear a 320x240 depth buffer to render in small 64x64 framebuffer)
580
// and adjust the area to the associated color buffer
581
// no need to optimize this search because it's rare (i.e. mainly depth clear,
582
// so once per frame)
583
for (j=chunk.renderBuffer->nbDepthSections-1; j>=0; j--) {
584
// LOG("j %d %d %d %d\n", j, i, chunk.renderBuffer->depthSections[j].chunkId,
585
// chunk.renderBuffer->depthSections[j].buffer - rBuffers);
586
if (i >= chunk.renderBuffer->depthSections[j].chunkId)
587
break;
588
}
589
//rglAssert(j < chunk.renderBuffer->nbDepthSections-1);
590
if (j < chunk.renderBuffer->nbDepthSections-1) {
591
rglRenderBuffer_t * cbuffer = chunk.renderBuffer->depthSections[j+1].buffer;
592
chunk.renderBuffer = rglSelectRenderBuffer(chunk.renderBuffer->addressStart, cbuffer->fbWidth, chunk.renderBuffer->size, chunk.renderBuffer->format);
593
chunk.renderBuffer->area = cbuffer->area;
594
chunk.renderBuffer->flags |= RGL_RB_DEPTH;
595
}
596
}
597
598
rglRenderBuffer_t & buffer = *chunk.renderBuffer;
599
int oldFlags = ~0;
600
int oldTilenum = ~0;
601
int combFormat = 0;
602
603
rglAssert(buffer.area.xh != 8192);
604
605
if (lastBuffer != &buffer)
606
rglPrepareFramebuffer(buffer);
607
608
DUMP("Buffer %p at %x area %d -> %d x %d -> %d\n",
609
&buffer, buffer.addressStart,
610
buffer.area.xh>>2, buffer.area.xl>>2,
611
buffer.area.yh>>2, buffer.area.yl>>2);
612
// if (buffer.addressStart != vi_origin)
613
// continue;
614
615
if (buffer.flags & RGL_RB_DEPTH)
616
chunk.depthAddress = buffer.addressStart;
617
618
if (lastBuffer != &buffer ||
619
lastDepthAddress != chunk.depthAddress) {
620
lastBuffer = &buffer;
621
lastDepthAddress = chunk.depthAddress;
622
int j;
623
for (j=0; j<nbRBuffers; j++) {
624
int overlap = int(rBuffers[j].addressStop) - int(buffer.addressStart);
625
if (int(buffer.addressStop) - int(rBuffers[j].addressStart) < overlap)
626
overlap = int(buffer.addressStop) - int(rBuffers[j].addressStart);
627
// LOG("checking #%d %x --> %x with %x --> %x overlap %x\n",
628
// j,
629
// rBuffers[j].addressStart, rBuffers[j].addressStop,
630
// buffer.addressStart, buffer.addressStop,
631
// overlap);
632
// check if more than 10% of the buffer was erased
633
if (rBuffers+j != &buffer &&
634
overlap > int(rBuffers[j].addressStop - rBuffers[j].addressStart)/10
635
// rBuffers[j].addressStop > buffer.addressStart &&
636
// rBuffers[j].addressStart < buffer.addressStop
637
) {
638
rBuffers[j].flags |= RGL_RB_ERASED;
639
DUMP("erasing fb #%d\n", j);
640
}
641
}
642
643
#ifndef NOFBO
644
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid);
645
646
rglDepthBuffer_t * zbuf = rglFindDepthBuffer(chunk.depthAddress,
647
buffer.fboWidth, buffer.fboHeight);
648
if (zbuf != buffer.depthBuffer) {
649
buffer.depthBuffer = zbuf;
650
#ifdef ZTEX
651
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
652
GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D,
653
buffer.depthBuffer->zbid, 0);
654
#else
655
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, buffer.depthBuffer->zbid );
656
#endif
657
// glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
658
// GL_RENDERBUFFER_EXT, depthBuffer->zbid );
659
660
CHECK_FRAMEBUFFER_STATUS();
661
}
662
#endif
663
664
glViewport(0, 0, buffer.realWidth, buffer.realHeight);
665
}
666
667
if (chunk.rdpState.clip.yl < chunk.rdpState.clip.yh ||
668
chunk.rdpState.clip.xl < chunk.rdpState.clip.xh)
669
continue;
670
671
glScissor((chunk.rdpState.clip.xh >>2)*buffer.realWidth/buffer.width,
672
(chunk.rdpState.clip.yh >>2)*buffer.realHeight/buffer.height,
673
((chunk.rdpState.clip.xl-chunk.rdpState.clip.xh) >>2)*buffer.realWidth/buffer.width,
674
((chunk.rdpState.clip.yl-chunk.rdpState.clip.yh) >>2)*buffer.realHeight/buffer.height);
675
rglAssert(glGetError() == GL_NO_ERROR);
676
677
#ifndef NOFBO
678
#ifdef RGL_EXACT_BLEND
679
glPushAttrib(GL_ALL_ATTRIB_BITS);
680
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid2);
681
glBindTexture(GL_TEXTURE_2D, buffer.texid);
682
glEnable(GL_TEXTURE_2D);
683
rglUseShader(rglCopyShader);
684
glColor4ub(255,255,255,255);
685
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
686
glDisable(GL_DEPTH_TEST);
687
688
for (j=0; j<chunk.nbStrips; j++) {
689
rglStrip_t & strip = chunk.strips[j];
690
int k;
691
692
glBegin(GL_TRIANGLE_STRIP);
693
for (k=0; k<strip.nbVtxs; k++) {
694
glTexCoord2f((strip.vtxs[k].x/(buffer.width)),
695
(strip.vtxs[k].y/(buffer.height)));
696
glVertex2f((strip.vtxs[k].x/(buffer.width)),
697
(strip.vtxs[k].y/(buffer.height)));
698
}
699
glEnd();
700
}
701
glBindTexture(GL_TEXTURE_2D, 0);
702
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid);
703
glPopAttrib();
704
#endif
705
#endif
706
707
if (buffer.flags & RGL_RB_DEPTH) {
708
DUMP("depth write\n");
709
//rglRenderMode(chunk);
710
glDepthMask(GL_TRUE);
711
glDepthFunc(GL_ALWAYS);
712
glDisable( GL_ALPHA_TEST );
713
glDisable( GL_POLYGON_OFFSET_FILL ); // ?
714
//glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
715
} else {
716
rglRenderMode(chunk);
717
}
718
rglAssert(glGetError() == GL_NO_ERROR);
719
720
if (RDP_GETOM_Z_MODE(chunk.rdpState.otherModes) & 1) {
721
switch(RDP_GETOM_Z_MODE(chunk.rdpState.otherModes)) {
722
case 3:
723
zb = 20;
724
break;
725
default:
726
zb = 4;
727
break;
728
}
729
} else {
730
zb = 0;
731
}
732
zb *= 16e-6f;
733
734
#ifdef RGL_EXACT_BLEND
735
glDisable(GL_BLEND);
736
glActiveTextureARB(GL_TEXTURE1_ARB);
737
glBindTexture(GL_TEXTURE_2D, buffer.texid2);
738
glEnable(GL_TEXTURE_2D);
739
rglAssert(glGetError() == GL_NO_ERROR);
740
glActiveTextureARB(GL_TEXTURE0_ARB);
741
#endif
742
743
combFormat = (buffer.size == 1? RGL_COMB_FMT_I : RGL_COMB_FMT_RGBA);
744
// not yet
745
// if (buffer.flags & RGL_RB_DEPTH)
746
// combFormat = RGL_COMB_FMT_DEPTH;
747
748
float ds[2], dt[2], ss[2], st[2];
749
float dsm[2], dtm[2];
750
for (j=0; j<chunk.nbStrips; j++) {
751
rglStrip_t & strip = chunk.strips[j];
752
int k;
753
int tilenum = strip.tilenum;
754
if (tilenum == 7 && RDP_GETOM_CYCLE_TYPE(chunk.rdpState.otherModes)==1) {
755
tilenum = 0;
756
combFormat |= RGL_COMB_TILE7;
757
}
758
759
rglTile_t & tile = chunk.tiles[tilenum];
760
rglTile_t & tile2 = chunk.tiles[tilenum+1];
761
762
if (strip.flags != oldFlags || tilenum != oldTilenum) {
763
oldTilenum = tilenum;
764
if (strip.flags & RGL_STRIP_TEX1) {
765
//if (tile.hiresBuffer) continue;
766
combFormat |= rglUseTile(tile, ds[0], dt[0], ss[0], st[0]);
767
glEnable(GL_TEXTURE_2D);
768
} else
769
glDisable(GL_TEXTURE_2D);
770
771
glActiveTextureARB(GL_TEXTURE2_ARB);
772
if (strip.flags & RGL_STRIP_TEX2) {
773
//if (tile2.hiresBuffer) continue;
774
combFormat |= rglUseTile(tile2, ds[1], dt[1], ss[1], st[1]) << 1;
775
glEnable(GL_TEXTURE_2D);
776
} else
777
glDisable(GL_TEXTURE_2D);
778
glActiveTextureARB(GL_TEXTURE0_ARB);
779
}
780
781
if (j == 0)
782
rglSetCombiner(chunk, combFormat);
783
784
if (strip.flags != oldFlags) {
785
oldFlags = strip.flags;
786
if (strip.flags & RGL_STRIP_ZBUFFER)
787
glEnable(GL_DEPTH_TEST);
788
else
789
glDisable(GL_DEPTH_TEST);
790
791
if (!(strip.flags & RGL_STRIP_SHADE))
792
// TODO take in account the framebuffer size (16b or 32b)
793
glColor4f(RDP_GETC16_R(chunk.rdpState.fillColor)/31.0f,
794
RDP_GETC16_G(chunk.rdpState.fillColor)/31.0f,
795
RDP_GETC16_B(chunk.rdpState.fillColor)/31.0f,
796
RDP_GETC16_A(chunk.rdpState.fillColor));
797
798
if (wireframe) {
799
if (!(strip.flags & (RGL_STRIP_SHADE | RGL_STRIP_TEX1 | RGL_STRIP_TEX2)))
800
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
801
else
802
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
803
}
804
}
805
806
// FIXME
807
// if (RDP_GETOM_CYCLE_TYPE(curChunk->rdpState.otherModes) < 2)
808
// glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
809
// else
810
// glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
811
812
813
if (strip.flags & RGL_STRIP_TEX1)
814
rglFixupMapping(strip, tile,
815
ds[0], dt[0], ss[0], st[0], dsm[0], dtm[0],
816
(strip.flags & RGL_STRIP_TEX2) && tile.tex == tile2.tex);
817
if (strip.flags & RGL_STRIP_TEX2) {
818
glActiveTextureARB(GL_TEXTURE2_ARB);
819
rglFixupMapping(strip, tile2,
820
ds[1], dt[1], ss[1], st[1], dsm[1], dtm[1],
821
(strip.flags & RGL_STRIP_TEX1) && tile.tex == tile2.tex);
822
glActiveTextureARB(GL_TEXTURE0_ARB);
823
}
824
825
glBegin(GL_TRIANGLE_STRIP);
826
for (k=0; k<strip.nbVtxs; k++) {
827
if (strip.flags & RGL_STRIP_SHADE)
828
glColor4ub(strip.vtxs[k].r, strip.vtxs[k].g, strip.vtxs[k].b,
829
strip.vtxs[k].a);
830
if (strip.flags & RGL_STRIP_TEX1)
831
glMultiTexCoord2fARB(GL_TEXTURE0_ARB,
832
1-(strip.vtxs[k].s + ds[0] + dsm[0]) / ss[0],
833
1-(strip.vtxs[k].t + dt[0] + dtm[0]) / st[0]);
834
if (strip.flags & RGL_STRIP_TEX2)
835
glMultiTexCoord2fARB(GL_TEXTURE2_ARB,
836
1-(strip.vtxs[k].s + ds[1] + dsm[1]) / ss[1],
837
1-(strip.vtxs[k].t + dt[1] + dtm[1]) / st[1]);
838
#ifdef RGL_EXACT_BLEND
839
// glMultiTexCoord2fARB(GL_TEXTURE1_ARB,
840
// (strip.vtxs[k].x/(buffer.width))/**strip.vtxs[k].w*/,
841
// (strip.vtxs[k].y/(buffer.height))/**strip.vtxs[k].w*/);
842
// used only to pass the viewport information :/
843
// tried with light position --> but it seems less precise !
844
glMultiTexCoord2fARB(GL_TEXTURE1_ARB,
845
buffer.realWidth/2048.f,
846
buffer.realHeight/2048.f);
847
#endif
848
// if (ds || dt || ss!=1 || st!=1) {
849
// printf("%g x %g --> %g x %g\n",
850
// strip.vtxs[k].s*tile.w,
851
// strip.vtxs[k].t*tile.h,
852
// (strip.vtxs[k].s + ds) * ss,
853
// (strip.vtxs[k].t + dt) * st);
854
// }
855
856
float
857
x = strip.vtxs[k].x*strip.vtxs[k].w,
858
y = strip.vtxs[k].y*strip.vtxs[k].w;
859
860
if (buffer.flags & RGL_RB_DEPTH)
861
glVertex3f((strip.vtxs[k].x/(buffer.width)),
862
(strip.vtxs[k].y/(buffer.height)),
863
//rglZscale(chunk.rdpState.fillColor&0xffff));
864
float(chunk.rdpState.fillColor&0xffff)/0xffff);
865
// glVertex4f((strip.vtxs[k].x/(buffer.width))*strip.vtxs[k].w,
866
// (strip.vtxs[k].y/(buffer.height))*strip.vtxs[k].w,
867
// float(chunk.rdpState.fillColor&0xffff)/0xffff*strip.vtxs[k].w,
868
// strip.vtxs[k].w);
869
else {
870
// glVertex4f(x/buffer.width, y/buffer.height,
871
// (strip.vtxs[k].z - 1.5f*zb)*(strip.vtxs[k].w),
872
// strip.vtxs[k].w);
873
874
float iw = strip.vtxs[k].w;
875
if (iw > 1000) {
876
glVertex4f(x/buffer.width, y/buffer.height,
877
(strip.vtxs[k].z - 1.5f*zb)*strip.vtxs[k].w,
878
strip.vtxs[k].w);
879
} else {
880
iw = 1.0f/iw;
881
glVertex4f(x/buffer.width, y/buffer.height,
882
(strip.vtxs[k].z) / (iw + zb*0.35f),
883
strip.vtxs[k].w);
884
}
885
// glVertex4f(x/buffer.width, y/buffer.height,
886
// (strip.vtxs[k].z)*strip.vtxs[k].w,
887
// strip.vtxs[k].w);
888
}
889
890
if (x < chunk.rdpState.clip.xh/4)
891
x = chunk.rdpState.clip.xh/4;
892
if (x > chunk.rdpState.clip.xl/4)
893
x = chunk.rdpState.clip.xl/4;
894
if (y < chunk.rdpState.clip.yh/4)
895
y = chunk.rdpState.clip.yh/4;
896
if (y > chunk.rdpState.clip.yl/4)
897
y = chunk.rdpState.clip.yl/4;
898
if (buffer.mod.xh > x)
899
buffer.mod.xh = x;
900
if (buffer.mod.xl < x)
901
buffer.mod.xl = x;
902
if (buffer.mod.yh > y)
903
buffer.mod.yh = y;
904
if (buffer.mod.yl < y)
905
buffer.mod.yl = y;
906
907
}
908
glEnd();
909
910
// FIXME
911
// glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
912
913
}
914
915
buffer.flags |= RGL_RB_FBMOD;
916
917
#ifdef RGL_EXACT_BLEND
918
glActiveTextureARB(GL_TEXTURE1_ARB);
919
glDisable(GL_TEXTURE_2D);
920
glBindTexture(GL_TEXTURE_2D, 0);
921
glActiveTextureARB(GL_TEXTURE0_ARB);
922
#endif
923
}
924
925
glActiveTextureARB(GL_TEXTURE2_ARB);
926
glDisable(GL_TEXTURE_2D);
927
glBindTexture(GL_TEXTURE_2D, 0);
928
glActiveTextureARB(GL_TEXTURE0_ARB);
929
930
renderedChunks = i;
931
}
932
933
void rglDisplayFramebuffers()
934
{
935
if (!(vi_control & 3))
936
return;
937
938
#ifdef RDP_DEBUG
939
extern int nbFullSync;
940
LOG("nbFyllSync %d\n", nbFullSync);
941
nbFullSync = 0;
942
#endif
943
944
int height = (vi_control & 0x40) ? 480 : 240;
945
int width = vi_width;
946
947
// from glide64
948
DWORD scale_x = *gfx.VI_X_SCALE_REG & 0xFFF;
949
if (!scale_x) return;
950
DWORD scale_y = *gfx.VI_Y_SCALE_REG & 0xFFF;
951
if (!scale_y) return;
952
953
float fscale_x = (float)scale_x / 1024.0f;
954
float fscale_y = (float)scale_y / 1024.0f;
955
956
DWORD dwHStartReg = *gfx.VI_H_START_REG;
957
DWORD dwVStartReg = *gfx.VI_V_START_REG;
958
959
DWORD hstart = dwHStartReg >> 16;
960
DWORD hend = dwHStartReg & 0xFFFF;
961
962
// dunno... but sometimes this happens
963
if (hend == hstart) {
964
LOG("fix hend\n");
965
hend = (int)(*gfx.VI_WIDTH_REG / fscale_x);
966
}
967
968
if (hstart > hend) {
969
DWORD tmp=hstart; hstart=hend; hend=tmp;
970
LOG("swap hstart hend\n");
971
}
972
973
DWORD vstart = dwVStartReg >> 16;
974
DWORD vend = dwVStartReg & 0xFFFF;
975
976
if (vstart > vend) {
977
DWORD tmp=vstart; vstart=vend; vend=tmp;
978
LOG("swap vstart vend\n");
979
}
980
981
//if (*gfx.VI_WIDTH_REG != 0x500)
982
if (*gfx.VI_WIDTH_REG < 0x400)
983
fscale_y /= 2.0f;
984
985
// fscale_x *= screen_width / float(vi_width);
986
// fscale_y *= screen_height / height;
987
//glViewport(0*hstart*fscale_x, 0*vstart*fscale_y, (hend-hstart)*fscale_x, (vend-vstart)*fscale_y);
988
width = (hend-hstart)*fscale_x;
989
height = (vend-vstart)*fscale_y;
990
if (!width || !height) return;
991
static int oldw, oldh;
992
if (width == oldw && width > 200)
993
rglScreenWidth = width;
994
if (height == oldh && height > 200)
995
rglScreenHeight = height;
996
oldw = width;
997
oldh = height;
998
int vi_line = vi_width * 2; // TODO take in account the format
999
int vi_start = *gfx.VI_ORIGIN_REG;// - vi_line;
1000
int vi_stop = vi_start + height * vi_line;
1001
1002
1003
if (*gfx.VI_WIDTH_REG >= 0x400)
1004
vi_line /= 2;
1005
1006
DUMP("%x screen %x --> %x %d --> %d x %d --> %d scale %g x %g clip %g --> %g x %g --> %g %dx%d\n",
1007
vi_line,
1008
vi_start, vi_stop,
1009
hstart, hend, vstart, vend,
1010
fscale_x, fscale_y,
1011
hstart*fscale_x, hend*fscale_x, vstart*fscale_y, vend*fscale_y,
1012
width, height
1013
);
1014
1015
1016
#ifdef NOFBO
1017
return;
1018
#endif
1019
1020
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1021
glDrawBuffer(GL_BACK);
1022
glViewport(0, viewportOffset, screen_width, screen_height);
1023
glDisable(GL_SCISSOR_TEST);
1024
// wine seems to catch scissor test disabling so need to define an area nevertheless
1025
glScissor(0, viewportOffset, screen_width, screen_height);
1026
glClearColor(0, 0, 0, 0);
1027
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1028
glClear(GL_COLOR_BUFFER_BIT); // TODO clear a minimal area
1029
1030
rglRenderBuffer_t * buffer;
1031
CIRCLEQ_FOREACH(rglRenderBuffer_t, buffer, &rBufferHead, link)
1032
if (!(buffer->flags & RGL_RB_ERASED) &&
1033
(uint32_t)vi_stop > buffer->addressStart &&
1034
(uint32_t)vi_start < buffer->addressStop) {
1035
1036
if (buffer->size != 2 || buffer->format != RDP_FORMAT_RGBA)
1037
continue; // FIXME
1038
1039
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1040
glDrawBuffer(GL_BACK);
1041
glViewport(0, viewportOffset, screen_width, screen_height);
1042
1043
glDisable(GL_SCISSOR_TEST);
1044
// wine seems to catch scissor test disabling so need to define an area nevertheless
1045
glScissor(0, viewportOffset, screen_width, screen_height);
1046
1047
glDisable(GL_ALPHA_TEST);
1048
glDisable(GL_BLEND);
1049
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1050
glActiveTextureARB(GL_TEXTURE1_ARB);
1051
glDisable(GL_TEXTURE_2D);
1052
glActiveTextureARB(GL_TEXTURE0_ARB);
1053
1054
1055
1056
float x = (int32_t(buffer->addressStart - vi_start) % int(vi_line)) / 2;
1057
float y = height - buffer->height - (int32_t(buffer->addressStart - vi_start) / int(vi_line));
1058
//x=y=0;
1059
DUMP("displaying fb %x %d x %d (%d x %d) at %g x %g\n", buffer->addressStart,
1060
buffer->width, buffer->height,
1061
buffer->realWidth, buffer->realHeight,
1062
x, y);
1063
y -= *gfx.VI_V_CURRENT_LINE_REG & 1; // prevent interlaced modes flickering
1064
x = x / width;
1065
y = y / height;
1066
rglUseShader(rglCopyShader);
1067
glBindTexture(GL_TEXTURE_2D, buffer->texid);
1068
glEnable(GL_TEXTURE_2D);
1069
glDisable(GL_DEPTH_TEST);
1070
glDisable(GL_BLEND);
1071
glColor4ub(255, 255, 255, 255);
1072
glBegin(GL_TRIANGLE_STRIP);
1073
glTexCoord2f(float(buffer->realWidth)/buffer->fboWidth, float(buffer->realHeight)/buffer->fboHeight); glVertex2f(x+float(buffer->width-1)/(width-1), y+0);
1074
glTexCoord2f(0, float(buffer->realHeight)/buffer->fboHeight); glVertex2f(x+0, y+0);
1075
glTexCoord2f(float(buffer->realWidth)/buffer->fboWidth, 0); glVertex2f(x+float(buffer->width-1)/(width-1), y+float(buffer->height-1)/(height-1));
1076
glTexCoord2f(0, 0); glVertex2f(x+0, y+float(buffer->height-1)/(height-1));
1077
glEnd();
1078
}
1079
}
1080
1081
void rglUpdate()
1082
{
1083
int i;
1084
1085
if (old_vi_origin == vi_origin) {
1086
//printf("same\n");
1087
return;
1088
}
1089
old_vi_origin = vi_origin;
1090
1091
DUMP("updating vi_origin %x vi_hstart %d vi_vstart %d\n",
1092
vi_origin, *gfx.VI_H_START_REG, *gfx.VI_V_START_REG);
1093
1094
glPolygonMode(GL_FRONT_AND_BACK, wireframe? GL_LINE : GL_FILL);
1095
1096
rglRenderChunks(nbChunks);
1097
1098
rglDisplayFramebuffers();
1099
1100
#ifndef NOFBO
1101
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1102
#endif
1103
rglUseShader(0);
1104
glDrawBuffer(GL_BACK);
1105
rglSwapBuffers();
1106
1107
rglFrameCounter++;
1108
1109
// for (i=0; i<nbRBuffers; i++)
1110
// rglFramebuffer2Rdram(rBuffers[i],
1111
// rBuffers[i].addressStart, rBuffers[i].addressStop);
1112
1113
1114
#ifdef RDP_DEBUG
1115
if (rdp_dump) {
1116
LOG("DUMP %d\n", rdp_dump);
1117
rdp_dump--;
1118
}
1119
#ifdef WIN32
1120
if (GetAsyncKeyState ('P') & 0x0001) {
1121
rglDebugger();
1122
}
1123
if (GetAsyncKeyState ('D') & 0x0001) {
1124
rdp_dump = 2;
1125
}
1126
if (GetAsyncKeyState ('W') & 0x0001) {
1127
wireframe = !wireframe;
1128
}
1129
#else
1130
SDL_Event event;
1131
while (nbChunks && SDL_PollEvent(&event)) {
1132
switch (event.type) {
1133
case SDL_KEYDOWN:
1134
switch (event.key.keysym.sym) {
1135
case 'd':
1136
rdp_dump = 2;
1137
break;
1138
case 'w': {
1139
wireframe = !wireframe;
1140
break;
1141
}
1142
case 'p': {
1143
rglDebugger();
1144
break;
1145
}
1146
}
1147
break;
1148
}
1149
}
1150
#endif
1151
#endif
1152
1153
#ifdef RDP_DEBUG
1154
rdpTracePos = 0;
1155
#endif
1156
1157
renderedChunks = 0;
1158
nbChunks = 0;
1159
nbStrips = 0;
1160
nbVtxs = 0;
1161
1162
for (i=0; i<nbRBuffers; i++) {
1163
rglRenderBuffer_t & buffer = rBuffers[i];
1164
buffer.area.xl = buffer.area.yl = 0;
1165
buffer.area.xh = buffer.area.yh = 8192;
1166
buffer.chunkId = 0;
1167
buffer.nbDepthSections = 0;
1168
}
1169
1170
// force a render buffer update
1171
rdpChanged |= (RDP_BITS_ZB_SETTINGS | RDP_BITS_FB_SETTINGS);
1172
}
1173
1174
void rglClearRenderBuffers()
1175
{
1176
int i;
1177
for (i=0; i<nbRBuffers; i++)
1178
rglDeleteRenderBuffer(rBuffers[i]);
1179
for (i=0; i<nbZBuffers; i++) {
1180
glDeleteRenderbuffersEXT(1, &zBuffers[i].zbid);
1181
zBuffers[i].zbid = 0;
1182
}
1183
1184
for (i=0; i<MAX_RENDER_BUFFERS; i++) {
1185
rglRenderBuffer_t & buffer = rBuffers[i];
1186
buffer.mod.xl = buffer.mod.yl = 0;
1187
buffer.mod.xh = buffer.mod.yh = 8192;
1188
buffer.area.xl = buffer.area.yl = 0;
1189
buffer.area.xh = buffer.area.yh = 8192;
1190
}
1191
1192
CIRCLEQ_INIT(rglRenderBuffer_t, &rBufferHead);
1193
1194
nbRBuffers = 0;
1195
nbZBuffers = 0;
1196
curRBuffer = 0;
1197
curZBuffer = 0;
1198
}
1199
1200
rglRenderBuffer_t * rglSelectRenderBuffer(uint32_t addr, int width, int size, int format)
1201
{
1202
int i;
1203
for (i=nbRBuffers-1; i>=0; i--)
1204
if (rBuffers[i].addressStart == addr &&
1205
rBuffers[i].fbWidth == width &&
1206
rBuffers[i].size == size)
1207
break;
1208
1209
if (i >= 0) {
1210
return rBuffers + i;
1211
// TODO need to take care of framebuffer format possible change (?)
1212
}
1213
1214
rglAssert(nbRBuffers < MAX_RENDER_BUFFERS);
1215
// if (nbRBuffers == MAX_RENDER_BUFFERS)
1216
// rglClearRenderBuffers();
1217
1218
i = nbRBuffers++;
1219
rglRenderBuffer_t * cur = rBuffers + i;
1220
1221
cur->addressStart = addr;
1222
cur->format = format;
1223
cur->size = size;
1224
cur->fbWidth = width;
1225
cur->area = rdpState.clip;
1226
cur->line = (width << size >> 1);
1227
cur->flags = 0;
1228
CIRCLEQ_INSERT_HEAD(rglRenderBuffer_t, &rBufferHead, cur, link);
1229
return cur;
1230
}
1231
1232
void rglPrepareRendering(int texturing, int tilenum, int recth, int depth)
1233
{
1234
if (!rdpChanged)
1235
goto ok;
1236
1237
//rglUpdate();
1238
1239
depth = /*depth && */(RDP_GETOM_CYCLE_TYPE(rdpState.otherModes) < 2) &&
1240
(RDP_GETOM_Z_UPDATE_EN(rdpState.otherModes) ||
1241
RDP_GETOM_Z_COMPARE_EN(rdpState.otherModes));
1242
1243
if (curRBuffer)
1244
curRBuffer->chunkId = nbChunks;
1245
1246
if (!curZBuffer ||
1247
(rdpChanged & (RDP_BITS_ZB_SETTINGS | RDP_BITS_FB_SETTINGS)) ||
1248
curZBuffer->addressStart != rdpZbAddress) {
1249
// first search the most recent without considering the width of the buffer
1250
rglRenderBuffer_t * buf;
1251
curZBuffer = 0;
1252
CIRCLEQ_FOREACH(rglRenderBuffer_t, buf, &rBufferHead, link)
1253
if (buf->addressStart == rdpZbAddress) {
1254
curZBuffer = buf;
1255
break;
1256
}
1257
if (!curZBuffer) {
1258
curZBuffer = rglSelectRenderBuffer(rdpZbAddress, rdpFbWidth, 2, RDP_FORMAT_RGBA);
1259
CIRCLEQ_REMOVE(&rBufferHead, curZBuffer, link);
1260
CIRCLEQ_INSERT_HEAD(rglRenderBuffer_t, &rBufferHead, curZBuffer, link);
1261
}
1262
}
1263
1264
if (rdpChanged & (RDP_BITS_ZB_SETTINGS | RDP_BITS_FB_SETTINGS)) {
1265
curRBuffer = rglSelectRenderBuffer(rdpFbAddress, rdpFbWidth, rdpFbSize, rdpFbFormat);
1266
CIRCLEQ_REMOVE(&rBufferHead, curRBuffer, link);
1267
CIRCLEQ_INSERT_HEAD(rglRenderBuffer_t, &rBufferHead, curRBuffer, link);
1268
}
1269
1270
if (rdpChanged & (RDP_BITS_TMEM | RDP_BITS_TLUT | RDP_BITS_TILE_SETTINGS))
1271
rglTouchTMEM();
1272
1273
if (rdpChanged & (RDP_BITS_CLIP | RDP_BITS_ZB_SETTINGS | RDP_BITS_FB_SETTINGS) &&
1274
rdpState.clip.xh <= rdpState.clip.xl && rdpState.clip.yh <= rdpState.clip.yl)
1275
{
1276
if (curRBuffer->area.xh == 8192)
1277
curRBuffer->flags &= ~RGL_RB_HASTRIANGLES;
1278
1279
if (curRBuffer->area.xh > rdpState.clip.xh)
1280
curRBuffer->area.xh = rdpState.clip.xh;
1281
if (curRBuffer->area.xl < rdpState.clip.xl)
1282
curRBuffer->area.xl = rdpState.clip.xl;
1283
if (curRBuffer->area.yh > rdpState.clip.yh)
1284
curRBuffer->area.yh = rdpState.clip.yh;
1285
if (curRBuffer->area.yl < rdpState.clip.yl)
1286
curRBuffer->area.yl = rdpState.clip.yl;
1287
}
1288
1289
curRBuffer->chunkId = nbChunks; // don't include THIS chunk yet in case of feedback rendering (cf CBFD)
1290
// if (curZBuffer)
1291
// curZBuffer->chunkId = nbChunks;
1292
1293
curChunk = chunks + nbChunks++;
1294
rglAssert(nbChunks < MAX_RENDER_CHUNKS);
1295
1296
curChunk->strips = strips + nbStrips;
1297
curChunk->nbStrips = 0;
1298
curChunk->renderBuffer = curRBuffer;
1299
curChunk->flags = 0;
1300
curChunk->rdpState = rdpState;
1301
curChunk->depthAddress = rdpZbAddress;
1302
1303
#ifdef RDP_DEBUG
1304
curChunk->tracePos = rdpTracePos;
1305
#endif
1306
1307
if (depth) {
1308
curZBuffer->flags |= RGL_RB_DEPTH;
1309
//rglRenderChunks(curZBuffer);
1310
1311
if (rdpFbAddress != rdpZbAddress) {
1312
if (!curZBuffer->nbDepthSections ||
1313
curZBuffer->depthSections[curZBuffer->nbDepthSections-1].buffer != curRBuffer) {
1314
rglAssert(curZBuffer->nbDepthSections < RGL_MAX_DEPTH_SECTIONS);
1315
curZBuffer->depthSections[curZBuffer->nbDepthSections].buffer = curRBuffer;
1316
curZBuffer->nbDepthSections++;
1317
}
1318
curZBuffer->depthSections[curZBuffer->nbDepthSections-1].chunkId = nbChunks;
1319
}
1320
}
1321
1322
{
1323
// eliminate useless bits
1324
int cycle = RDP_GETOM_CYCLE_TYPE(curChunk->rdpState.otherModes);
1325
curChunk->rdpState.otherModes.w2 &= rdpBlendMasks[cycle].w2;
1326
curChunk->rdpState.combineModes.w1 &= rdpCombineMasks[cycle].w1;
1327
curChunk->rdpState.combineModes.w2 &= rdpCombineMasks[cycle].w2;
1328
}
1329
1330
rdpChanged = 0;
1331
1332
ok:
1333
if (texturing && !(curChunk->flags & (1<<tilenum))) {
1334
curChunk->flags |= (1<<tilenum);
1335
rglTile(rdpTiles[tilenum], curChunk->tiles[tilenum], recth);
1336
}
1337
}
1338
1339
1340
void rglClose()
1341
{
1342
1343
#ifdef RDP_DEBUG
1344
rglCloseDebugger();
1345
#endif
1346
1347
rglClearRenderBuffers();
1348
1349
rglResetTextureCache();
1350
1351
nbChunks = 0;
1352
nbStrips = 0;
1353
nbVtxs = 0;
1354
1355
if (rglCopyShader) rglDeleteShader(rglCopyShader);
1356
rglCopyShader = 0;
1357
if (rglCopyDepthShader) rglDeleteShader(rglCopyDepthShader);
1358
rglCopyDepthShader = 0;
1359
rglClearCombiners();
1360
}
1361
1362
1363
int rglInit()
1364
{
1365
static int init;
1366
if (!init) {
1367
init = 1;
1368
glewInit();
1369
}
1370
1371
glViewport(0, 0, screen_width, screen_height);
1372
1373
glLoadIdentity();
1374
#ifdef NOFBO
1375
glScalef(2, -2, 1);
1376
#else
1377
glScalef(2, 2, 1);
1378
#endif
1379
glTranslatef(-0.5, -0.5, 0);
1380
1381
glEnable(GL_DEPTH_TEST);
1382
1383
rglClose();
1384
1385
rglCopyShader = rglCreateShader(
1386
"void main() \n"
1387
"{ \n"
1388
" gl_Position = ftransform(); \n"
1389
" gl_FrontColor = gl_Color; \n"
1390
" gl_TexCoord[0] = gl_MultiTexCoord0; \n"
1391
"} \n"
1392
,
1393
"uniform sampler2D texture0; \n"
1394
" \n"
1395
"void main() \n"
1396
"{ \n"
1397
" gl_FragColor = gl_Color * texture2D(texture0, vec2(gl_TexCoord[0])); \n"
1398
"} \n"
1399
);
1400
1401
rglCopyDepthShader = rglCreateShader(
1402
"void main() \n"
1403
"{ \n"
1404
" gl_Position = ftransform(); \n"
1405
" gl_FrontColor = gl_Color; \n"
1406
" gl_TexCoord[0] = gl_MultiTexCoord0; \n"
1407
"} \n"
1408
,
1409
"uniform sampler2D texture0; \n"
1410
" \n"
1411
"void main() \n"
1412
"{ \n"
1413
" gl_FragDepth = texture2D(texture0, vec2(gl_TexCoord[0]))[0]; \n"
1414
"} \n"
1415
);
1416
1417
rdpChanged = ~0;
1418
return 1;
1419
}
1420
1421
1422
#ifdef __cplusplus
1423
extern "C" {
1424
#endif
1425
1426
EXPORT void CALL FBWrite(DWORD addr, DWORD size)
1427
{
1428
if (!rglSettings.fbInfo || rglSettings.async)
1429
return;
1430
//LOG("FBWrite %x\n", addr);
1431
rglRenderBuffer_t * buffer;
1432
addr &= 0x7fffff;
1433
CIRCLEQ_FOREACH(rglRenderBuffer_t, buffer, &rBufferHead, link) {
1434
if (addr >= buffer->addressStart && addr+size <= buffer->addressStop) {
1435
//LOG("FBWrite in fb #%d\n", buffer - rBuffers);
1436
buffer->flags &= ~RGL_RB_FBMOD;
1437
buffer->mod.xl = buffer->mod.yl = 0;
1438
buffer->mod.xh = buffer->mod.yh = 8192;
1439
//break;
1440
}
1441
}
1442
//LOG("FBWrite %x %d\n", addr, size);
1443
}
1444
1445
//EXPORT void CALL FBWList(FrameBufferModifyEntry *plist, DWORD size)
1446
//{
1447
// LOG("FBWList size %d\n", size);
1448
//}
1449
1450
EXPORT void CALL FBRead(DWORD addr)
1451
{
1452
if (!rglSettings.fbInfo || rglSettings.async)
1453
return;
1454
//LOG("FBRead %x\n", addr);
1455
rglRenderBuffer_t * buffer;
1456
addr &= 0x7fffff;
1457
CIRCLEQ_FOREACH(rglRenderBuffer_t, buffer, &rBufferHead, link) {
1458
if (addr >= buffer->addressStart && addr < buffer->addressStop) {
1459
// LOG("writing to rdram buffer %x --> %x\n",
1460
// buffer->addressStart, buffer->addressStop);
1461
rglFramebuffer2Rdram(*buffer, buffer->addressStart, buffer->addressStop);
1462
break;
1463
}
1464
}
1465
}
1466
1467
EXPORT void CALL FBGetFrameBufferInfo(void *p)
1468
{
1469
typedef struct
1470
{
1471
DWORD addr;
1472
DWORD size;
1473
DWORD width;
1474
DWORD height;
1475
} FrameBufferInfo;
1476
1477
FrameBufferInfo * pinfo = (FrameBufferInfo *)p;
1478
int i;
1479
1480
if (!rglSettings.fbInfo)
1481
return;
1482
//LOG("GetFbInfo\n");
1483
1484
rglRenderBuffer_t * buffer;
1485
i=0;
1486
CIRCLEQ_FOREACH(rglRenderBuffer_t, buffer, &rBufferHead, link) {
1487
// printf("#%d (%dx%d) %x --> %x\n", i,
1488
// buffer->width, buffer->height,
1489
// buffer->addressStart,
1490
// buffer->addressStart + buffer->width*buffer->height*2);
1491
pinfo[i].addr = buffer->addressStart;
1492
pinfo[i].size = 2; // FIXME
1493
pinfo[i].width = buffer->width;
1494
pinfo[i].height = buffer->height;
1495
i++; if (i>=6) break;
1496
}
1497
for ( ; i<6; i++) {
1498
pinfo[i].addr = 0;
1499
pinfo[i].size = 0;
1500
pinfo[i].width = 4;
1501
pinfo[i].height = 4;
1502
}
1503
}
1504
1505
1506
#ifdef __cplusplus
1507
}
1508
#endif
1509
1510
static char exptable[256];
1511
1512
static void build_exptable()
1513
{
1514
LOG("Building depth exp table\n");
1515
int i;
1516
for (i=0; i<256; i++) {
1517
int s;
1518
for (s=0; s<7; s++)
1519
if (!(i&(1<<(6-s))))
1520
break;
1521
exptable[i] = s;
1522
}
1523
}
1524
1525
void rglFramebuffer2Rdram(rglRenderBuffer_t & buffer, uint32_t start, uint32_t stop)
1526
{
1527
int depth;
1528
1529
rglRenderChunks(&buffer);
1530
1531
if (!(buffer.flags & RGL_RB_FBMOD))
1532
return;
1533
1534
// if (buffer.area.xh == 8192)
1535
// return;
1536
// rglAssert (buffer.area.xh != 8192);
1537
1538
depth = buffer.flags & RGL_RB_DEPTH;
1539
//depth = 1;
1540
1541
int glfmt, packed;
1542
int x, y;
1543
int rw, rh;
1544
int rx, ry;
1545
uint8_t * ram = gfx.RDRAM + buffer.addressStart;
1546
static uint8_t * fb = rglTmpTex;
1547
if (depth) {
1548
glfmt = GL_DEPTH_COMPONENT;
1549
//packed = GL_UNSIGNED_SHORT;
1550
packed = GL_FLOAT;
1551
} else {
1552
glfmt = GL_RGBA;
1553
packed = GL_UNSIGNED_BYTE;
1554
}
1555
1556
rx = buffer.mod.xh;
1557
ry = buffer.mod.yh;
1558
rw = (int(buffer.mod.xl) - int(buffer.mod.xh));
1559
rh = (int(buffer.mod.yl) - int(buffer.mod.yh));
1560
1561
if (rw > buffer.fbWidth)
1562
rw = buffer.fbWidth;
1563
1564
LOG("writing to rdram %x %s-%d %d %dx%d %dx%d %dx%d\n",
1565
buffer.addressStart, depth? "depth":rdpImageFormats[buffer.format], buffer.size,
1566
buffer.fbWidth,
1567
buffer.width, buffer.height,
1568
rx, ry,
1569
rw, rh);
1570
fflush(stderr);
1571
1572
if (rw <= 0 || rh <= 0)
1573
return;
1574
1575
// rx=ry=0;
1576
// rw = buffer.width;
1577
// rh = buffer.height;
1578
1579
glPushAttrib(GL_ALL_ATTRIB_BITS);
1580
#ifndef NOFBO
1581
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1582
#endif
1583
glDrawBuffer(GL_BACK);
1584
glReadBuffer(GL_BACK);
1585
glDisable(GL_SCISSOR_TEST);
1586
glViewport(0, 0, buffer.width, buffer.height); // FIXME why +1 ?
1587
// wine seems to catch scissor test disabling so need to define an area nevertheless
1588
glScissor(0, 0, buffer.width+1, buffer.height+1);
1589
glEnable(GL_TEXTURE_2D);
1590
glDisable( GL_ALPHA_TEST );
1591
if (depth) {
1592
glBindTexture(GL_TEXTURE_2D, buffer.depthBuffer->zbid);
1593
rglUseShader(rglCopyDepthShader);
1594
glEnable(GL_DEPTH_TEST);
1595
glDepthFunc(GL_ALWAYS);
1596
glDepthMask(GL_TRUE);
1597
glDisable( GL_POLYGON_OFFSET_FILL );
1598
} else {
1599
glBindTexture(GL_TEXTURE_2D, buffer.texid);
1600
rglUseShader(rglCopyShader);
1601
glDisable(GL_DEPTH_TEST);
1602
glDisable(GL_BLEND);
1603
glColor4ub(255, 255, 255, 255);
1604
}
1605
glBegin(GL_TRIANGLE_STRIP);
1606
glTexCoord2f(1, 1); glVertex2f(1, 1);
1607
glTexCoord2f(0, 1); glVertex2f(0, 1);
1608
glTexCoord2f(1, 0); glVertex2f(1, 0);
1609
glTexCoord2f(0, 0); glVertex2f(0, 0);
1610
glEnd();
1611
1612
glReadPixels(rx, ry, rw, rh,
1613
glfmt, packed,
1614
fb);
1615
1616
1617
if (depth) {
1618
if (!exptable[255])
1619
build_exptable();
1620
for (x=rx; x<rx+rw; x++)
1621
for (y=ry; y<ry+rh; y++) {
1622
uint32_t a = *(float *)&fb[(x-rx)*4 + (y-ry)*rw*4] * ((1<<18)-1);
1623
//uint32_t a = uint32_t(*(uint16_t *)&fb[(x-rx)*4 + (y-ry)*rw*4]) << 2;
1624
int e = exptable[a>>(18-8)];
1625
1626
a = ( ( (e>=6? a : (a>>(6-e))) & ((1<<11)-1) ) << 2 ) | (e<<(16-3));
1627
1628
*(uint16_t *)&ram[(x*2 + y*buffer.line) ^ 2] =
1629
a;
1630
//int(*(uint16_t *)&fb[(x-rx)*2 + (y-ry)*rw*2])-2;
1631
//(*(uint16_t *)&fb[(x-rx)*2 + (y-ry)*rw*2] - int(0x8000))*2;
1632
//(*(float *)&fb[(x-rx)*4 + (y-ry)*rw*4]-0.5)*0x1ffff;
1633
}
1634
} else {
1635
switch (buffer.size) {
1636
case 1:
1637
for (x=rx; x<rx+rw; x++)
1638
for (y=ry; y<ry+rh; y++) {
1639
int r = fb[(x-rx + (y-ry)*rw)*4 + 0];
1640
// int g = fb[(x-rx + (y-ry)*rw)*4 + 1];
1641
// int b = fb[(x-rx + (y-ry)*rw)*4 + 2];
1642
// int a = fb[(x-rx + (y-ry)*rw)*4 + 3];
1643
*(uint8_t *)&ram[(x + y*buffer.line) ^ 3] =
1644
r;
1645
//(r+g+b)/3; // FIXME just R ?
1646
}
1647
break;
1648
case 2:
1649
for (x=rx; x<rx+rw; x++)
1650
for (y=ry; y<ry+rh; y++) {
1651
int r = fb[(x-rx + (y-ry)*rw)*4 + 0];
1652
int g = fb[(x-rx + (y-ry)*rw)*4 + 1];
1653
int b = fb[(x-rx + (y-ry)*rw)*4 + 2];
1654
int a = fb[(x-rx + (y-ry)*rw)*4 + 3];
1655
*(uint16_t *)&ram[(x*2 + y*buffer.line) ^ 2] =
1656
((r&0xf8)<<8) | ((g&0xf8)<<3) | ((b&0xf8)>>2) |
1657
((a&0x80)>>7);
1658
}
1659
break;
1660
}
1661
}
1662
1663
buffer.mod.xl = buffer.mod.yl = 0;
1664
buffer.mod.xh = buffer.mod.yh = 8192;
1665
1666
//if (start <= buffer.addressStart && stop >= buffer.addressStop)
1667
buffer.flags &= ~RGL_RB_FBMOD;
1668
1669
glPopAttrib();
1670
}
1671
1672
void rglUpdateStatus()
1673
{
1674
if (rglNextStatus != rglStatus) {
1675
const char * status[] = { "closed", "windowed", "fullscreen" };
1676
LOG("Status %s --> %s\n", status[rglStatus], status[rglNextStatus]);
1677
rglCloseScreen();
1678
rglStatus = rglNextStatus;
1679
if (rglNextStatus != RGL_STATUS_CLOSED)
1680
rglOpenScreen();
1681
}
1682
}
1683
1684