Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/Cherry/Core/Video.cpp
2 views
1
/*
2
* Gearcoleco - ColecoVision Emulator
3
* Copyright (C) 2021 Ignacio Sanchez
4
5
* This program is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* any later version.
9
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
14
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see http://www.gnu.org/licenses/
17
*
18
*/
19
20
#include "Video.h"
21
#include "CVMemory.h"
22
#include "Processor.h"
23
24
Video::Video(CVMemory* pMemory, Processor* pProcessor)
25
{
26
m_pMemory = pMemory;
27
m_pProcessor = pProcessor;
28
InitPointer(m_pInfoBuffer);
29
InitPointer(m_pFrameBuffer);
30
InitPointer(m_pVdpVRAM);
31
m_bFirstByteInSequence = true;
32
for (int i = 0; i < 8; i++)
33
m_VdpRegister[i] = 0;
34
m_VdpBuffer = 0;
35
m_VdpAddress = 0;
36
m_iCycleCounter = 0;
37
m_VdpStatus = 0;
38
m_iLinesPerFrame = 0;
39
m_bPAL = false;
40
m_LineEvents.vint = false;
41
m_LineEvents.render = false;
42
m_LineEvents.display = false;
43
m_iRenderLine = 0;
44
m_iMode = 0;
45
m_bDisplayEnabled = false;
46
m_bSpriteOvrRequest = false;
47
m_bNoSpriteLimit = false;
48
49
for (int i = 0; i < 48; i++)
50
m_CustomPalette[i] = 0;
51
m_pCurrentPalette = const_cast<u8*>(kPalette_888_coleco);
52
}
53
54
Video::~Video()
55
{
56
SafeDeleteArray(m_pInfoBuffer);
57
SafeDeleteArray(m_pFrameBuffer);
58
SafeDeleteArray(m_pVdpVRAM);
59
}
60
61
void Video::Init()
62
{
63
m_pFrameBuffer = new u16[GC_RESOLUTION_WIDTH_WITH_OVERSCAN * GC_RESOLUTION_HEIGHT_WITH_OVERSCAN];
64
m_pInfoBuffer = new u8[GC_RESOLUTION_WIDTH * GC_LINES_PER_FRAME_PAL];
65
m_pVdpVRAM = new u8[0x4000];
66
InitPalettes();
67
Reset(false);
68
}
69
70
void Video::Reset(bool bPAL)
71
{
72
m_bPAL = bPAL;
73
m_iLinesPerFrame = bPAL ? GC_LINES_PER_FRAME_PAL : GC_LINES_PER_FRAME_NTSC;
74
m_bFirstByteInSequence = true;
75
m_VdpBuffer = 0;
76
m_VdpAddress = 0;
77
m_VdpStatus = 0;
78
79
for (int i = 0; i < (GC_RESOLUTION_WIDTH_WITH_OVERSCAN * GC_RESOLUTION_HEIGHT_WITH_OVERSCAN); i++)
80
m_pFrameBuffer[i] = 1;
81
for (int i = 0; i < (GC_RESOLUTION_WIDTH * GC_LINES_PER_FRAME_PAL); i++)
82
m_pInfoBuffer[i] = 0;
83
for (int i = 0; i < 0x4000; i++)
84
m_pVdpVRAM[i] = 0;
85
for (int i = 0; i < 8; i++)
86
m_VdpRegister[i] = 0;
87
88
m_bDisplayEnabled = false;
89
m_bSpriteOvrRequest = false;
90
91
m_LineEvents.vint = false;
92
m_LineEvents.display = false;
93
m_LineEvents.render = false;
94
95
m_iCycleCounter = 0;
96
m_iRenderLine = 0;
97
98
for (int i = 0; i < 128; i++)
99
m_SpriteAttribLatch[i] = 0;
100
101
m_Timing[TIMING_VINT] = 220;
102
m_Timing[TIMING_RENDER] = 195;
103
m_Timing[TIMING_DISPLAY] = 37;
104
}
105
106
void Video::SetNoSpriteLimit(bool noSpriteLimit)
107
{
108
m_bNoSpriteLimit = noSpriteLimit;
109
}
110
111
bool Video::Tick(unsigned int clockCycles)
112
{
113
bool return_vblank = false;
114
115
m_iCycleCounter += clockCycles;
116
117
///// VINT /////
118
if (m_iRenderLine == GC_RESOLUTION_HEIGHT)
119
{
120
if (!m_LineEvents.vint && (m_iCycleCounter >= m_Timing[TIMING_VINT]))
121
{
122
m_LineEvents.vint = true;
123
124
if (IsSetBit(m_VdpRegister[1], 5) && !IsSetBit(m_VdpStatus, 7))
125
m_pProcessor->RequestNMI();
126
127
m_VdpStatus = SetBit(m_VdpStatus, 7);
128
}
129
}
130
131
///// DISPLAY ON/OFF /////
132
if (!m_LineEvents.display && (m_iCycleCounter >= m_Timing[TIMING_DISPLAY]))
133
{
134
m_LineEvents.display = true;
135
m_bDisplayEnabled = IsSetBit(m_VdpRegister[1], 6);
136
}
137
138
///// RENDER /////
139
if (!m_LineEvents.render && (m_iCycleCounter >= m_Timing[TIMING_RENDER]))
140
{
141
m_LineEvents.render = true;
142
ScanLine(m_iRenderLine);
143
}
144
145
///// END OF LINE /////
146
if (m_iCycleCounter >= GC_CYCLES_PER_LINE)
147
{
148
LatchSpriteAttributes();
149
if (m_iRenderLine == GC_RESOLUTION_HEIGHT)
150
return_vblank = true;
151
m_iRenderLine++;
152
m_iRenderLine %= m_iLinesPerFrame;
153
m_iCycleCounter -= GC_CYCLES_PER_LINE;
154
m_LineEvents.vint = false;
155
m_LineEvents.render = false;
156
m_LineEvents.display = false;
157
}
158
159
return return_vblank;
160
}
161
162
u8 Video::GetDataPort()
163
{
164
m_bFirstByteInSequence = true;
165
u8 ret = m_VdpBuffer;
166
m_VdpBuffer = m_pVdpVRAM[m_VdpAddress];
167
m_VdpAddress = (m_VdpAddress + 1) & 0x3FFF;
168
return ret;
169
}
170
171
u8 Video::GetStatusFlags()
172
{
173
m_bFirstByteInSequence = true;
174
u8 ret = m_VdpStatus;
175
m_VdpStatus &= 0x1F;
176
177
if (IsSetBit(m_VdpRegister[1], 5) && IsSetBit(m_VdpStatus, 7))
178
{
179
m_pProcessor->RequestNMI();
180
}
181
182
return ret;
183
}
184
185
void Video::WriteData(u8 data)
186
{
187
m_bFirstByteInSequence = true;
188
m_VdpBuffer = data;
189
m_pVdpVRAM[m_VdpAddress] = data;
190
m_VdpAddress = (m_VdpAddress + 1) & 0x3FFF;
191
}
192
193
void Video::WriteControl(u8 control)
194
{
195
if (m_bFirstByteInSequence)
196
{
197
m_bFirstByteInSequence = false;
198
m_VdpAddress = (m_VdpAddress & 0x3F00) | control;
199
m_VdpBuffer = control;
200
}
201
else
202
{
203
m_bFirstByteInSequence = true;
204
m_VdpAddress = ((control & 0x3F) << 8) | m_VdpBuffer;
205
206
switch (control & 0xC0)
207
{
208
case 0x00:
209
{
210
m_VdpBuffer = m_pVdpVRAM[m_VdpAddress];
211
m_VdpAddress = (m_VdpAddress + 1) & 0x3FFF;
212
break;
213
}
214
case 0x80:
215
{
216
bool old_nmi = IsSetBit(m_VdpRegister[1], 5);
217
u8 masks[8] = { 0x03, 0xFB, 0x0F, 0xFF, 0x07, 0x7F, 0x07, 0xFF };
218
u8 reg = control & 0x07;
219
m_VdpRegister[reg] = m_VdpBuffer & masks[reg];
220
221
if ((reg == 1) && IsSetBit(m_VdpRegister[1], 5) && (!old_nmi) && IsSetBit(m_VdpStatus, 7))
222
{
223
m_pProcessor->RequestNMI();
224
}
225
226
if (reg < 2)
227
{
228
m_iMode = ((m_VdpRegister[1] & 0x08) >> 1) | (m_VdpRegister[0] & 0x02) | ((m_VdpRegister[1] & 0x10) >> 4);
229
}
230
231
break;
232
}
233
}
234
}
235
}
236
237
bool Video::IsPAL()
238
{
239
return m_bPAL;
240
}
241
242
u8 Video::GetBufferReg()
243
{
244
return m_VdpBuffer;
245
}
246
247
u16 Video::GetAddressReg()
248
{
249
return m_VdpAddress;
250
}
251
252
u8 Video::GetStatusReg()
253
{
254
return m_VdpStatus;
255
}
256
257
int Video::GetRenderLine()
258
{
259
return m_iRenderLine;
260
}
261
262
int Video::GetCycleCounter()
263
{
264
return m_iCycleCounter;
265
}
266
267
bool Video::GetLatch()
268
{
269
return m_bFirstByteInSequence;
270
}
271
272
void Video::ScanLine(int line)
273
{
274
if (m_bDisplayEnabled)
275
{
276
if (line < GC_RESOLUTION_HEIGHT)
277
{
278
RenderBackground(line);
279
280
if (m_iMode != 0x01)
281
RenderSprites(line);
282
}
283
}
284
else
285
{
286
if (line < GC_RESOLUTION_HEIGHT)
287
{
288
u16 color = m_VdpRegister[7] & 0x0F;
289
int line_width = line * GC_RESOLUTION_WIDTH;
290
291
for (int scx = 0; scx < GC_RESOLUTION_WIDTH; scx++)
292
{
293
int pixel = line_width + scx;
294
m_pFrameBuffer[pixel] = color;
295
m_pInfoBuffer[pixel] = 0;
296
}
297
}
298
}
299
}
300
301
void Video::LatchSpriteAttributes()
302
{
303
u16 sprite_attribute_addr = (m_VdpRegister[5] & 0x7F) << 7;
304
305
for (int i = 0; i < 128; i++)
306
m_SpriteAttribLatch[i] = m_pVdpVRAM[sprite_attribute_addr + i];
307
}
308
309
void Video::RenderBackground(int line)
310
{
311
int line_offset = line * GC_RESOLUTION_WIDTH;
312
313
int name_table_addr = m_VdpRegister[2] << 10;
314
int color_table_addr = m_VdpRegister[3] << 6;
315
int pattern_table_addr = m_VdpRegister[4] << 11;
316
int region_mask = ((m_VdpRegister[4] & 0x03) << 8) | 0xFF;
317
int color_mask = ((m_VdpRegister[3] & 0x7F) << 3) | 0x07;
318
int backdrop_color = m_VdpRegister[7] & 0x0F;
319
backdrop_color = (backdrop_color > 0) ? backdrop_color : 1;
320
321
int tile_y = line >> 3;
322
int tile_y_offset = line & 7;
323
int region = 0;
324
325
switch (m_iMode)
326
{
327
case 1:
328
{
329
int fg_color = (m_VdpRegister[7] >> 4) & 0x0F;
330
int bg_color = backdrop_color;
331
fg_color = (fg_color > 0) ? fg_color : backdrop_color;
332
333
for (int i = 0; i < 8; i++)
334
{
335
int pixel = line_offset + i;
336
m_pFrameBuffer[pixel] = bg_color;
337
m_pFrameBuffer[pixel + 248] = bg_color;
338
m_pInfoBuffer[pixel] = 0x00;
339
m_pInfoBuffer[pixel + 248] = 0x00;
340
}
341
342
for (int tile_x = 0; tile_x < 40; tile_x++)
343
{
344
int tile_number = (tile_y * 40) + tile_x;
345
int name_tile_addr = name_table_addr + tile_number;
346
int name_tile = m_pVdpVRAM[name_tile_addr];
347
u8 pattern_line = m_pVdpVRAM[pattern_table_addr + (name_tile << 3) + tile_y_offset];
348
349
int screen_offset = line_offset + (tile_x * 6) + 8;
350
351
for (int tile_pixel = 0; tile_pixel < 6; tile_pixel++)
352
{
353
int pixel = screen_offset + tile_pixel;
354
m_pFrameBuffer[pixel] = IsSetBit(pattern_line, 7 - tile_pixel) ? fg_color : bg_color;
355
m_pInfoBuffer[pixel] = 0x00;
356
}
357
}
358
return;
359
}
360
case 2:
361
{
362
pattern_table_addr &= 0x2000;
363
color_table_addr &= 0x2000;
364
region = (tile_y & 0x18) << 5;
365
break;
366
}
367
case 4:
368
{
369
pattern_table_addr &= 0x2000;
370
break;
371
}
372
}
373
374
for (int tile_x = 0; tile_x < 32; tile_x++)
375
{
376
int tile_number = (tile_y << 5) + tile_x;
377
int name_tile_addr = name_table_addr + tile_number;
378
int name_tile = m_pVdpVRAM[name_tile_addr];
379
u8 pattern_line = 0;
380
u8 color_line = 0;
381
382
if (m_iMode == 4)
383
{
384
int offset_color = pattern_table_addr + (name_tile << 3) + ((tile_y & 0x03) << 1) + (line & 0x04 ? 1 : 0);
385
color_line = m_pVdpVRAM[offset_color];
386
387
int left_color = color_line >> 4;
388
int right_color = color_line & 0x0F;
389
left_color = (left_color > 0) ? left_color : backdrop_color;
390
right_color = (right_color > 0) ? right_color : backdrop_color;
391
392
int screen_offset = line_offset + (tile_x << 3);
393
394
for (int tile_pixel = 0; tile_pixel < 4; tile_pixel++)
395
{
396
int pixel = screen_offset + tile_pixel;
397
m_pFrameBuffer[pixel] = left_color;
398
m_pInfoBuffer[pixel] = 0x00;
399
}
400
401
for (int tile_pixel = 4; tile_pixel < 8; tile_pixel++)
402
{
403
int pixel = screen_offset + tile_pixel;
404
m_pFrameBuffer[pixel] = right_color;
405
m_pInfoBuffer[pixel] = 0x00;
406
}
407
408
continue;
409
}
410
else if (m_iMode == 0)
411
{
412
pattern_line = m_pVdpVRAM[pattern_table_addr + (name_tile << 3) + tile_y_offset];
413
color_line = m_pVdpVRAM[color_table_addr + (name_tile >> 3)];
414
}
415
else if (m_iMode == 2)
416
{
417
name_tile += region;
418
pattern_line = m_pVdpVRAM[pattern_table_addr + ((name_tile & region_mask) << 3) + tile_y_offset];
419
color_line = m_pVdpVRAM[color_table_addr + ((name_tile & color_mask) << 3) + tile_y_offset];
420
}
421
422
int fg_color = color_line >> 4;
423
int bg_color = color_line & 0x0F;
424
fg_color = (fg_color > 0) ? fg_color : backdrop_color;
425
bg_color = (bg_color > 0) ? bg_color : backdrop_color;
426
427
int screen_offset = line_offset + (tile_x << 3);
428
429
for (int tile_pixel = 0; tile_pixel < 8; tile_pixel++)
430
{
431
int pixel = screen_offset + tile_pixel;
432
m_pFrameBuffer[pixel] = IsSetBit(pattern_line, 7 - tile_pixel) ? fg_color : bg_color;
433
m_pInfoBuffer[pixel] = 0x00;
434
}
435
}
436
}
437
438
void Video::RenderSprites(int line)
439
{
440
int sprite_count = 0;
441
int line_width = line * GC_RESOLUTION_WIDTH;
442
int sprite_size = IsSetBit(m_VdpRegister[1], 1) ? 16 : 8;
443
bool sprite_zoom = IsSetBit(m_VdpRegister[1], 0);
444
445
if (sprite_zoom)
446
sprite_size *= 2;
447
448
u16 sprite_pattern_addr = (m_VdpRegister[6] & 0x07) << 11;
449
450
int max_sprite = 31;
451
452
for (int sprite = 0; sprite <= max_sprite; sprite++)
453
{
454
int o = sprite << 2;
455
456
if (m_SpriteAttribLatch[o] == 0xD0)
457
{
458
max_sprite = sprite - 1;
459
break;
460
}
461
}
462
463
for (int sprite = 0; sprite <= max_sprite; sprite++)
464
{
465
int attrib_i = sprite << 2;
466
int sprite_y = (m_SpriteAttribLatch[attrib_i] + 1) & 0xFF;
467
468
if (sprite_y >= 0xE0)
469
sprite_y = -(0x100 - sprite_y);
470
471
if ((sprite_y > line) || ((sprite_y + sprite_size) <= line))
472
continue;
473
474
sprite_count++;
475
476
if (!IsSetBit(m_VdpStatus, 6) && (sprite_count > 4))
477
{
478
m_VdpStatus = SetBit(m_VdpStatus, 6);
479
m_VdpStatus = (m_VdpStatus & 0xE0) | sprite;
480
}
481
482
int sprite_color = m_SpriteAttribLatch[attrib_i + 3] & 0x0F;
483
484
if (sprite_color == 0)
485
continue;
486
487
int sprite_shift = (m_SpriteAttribLatch[attrib_i + 3] & 0x80) ? 32 : 0;
488
int sprite_x = m_SpriteAttribLatch[attrib_i + 1] - sprite_shift;
489
490
if (sprite_x >= GC_RESOLUTION_WIDTH)
491
continue;
492
493
int sprite_tile = m_SpriteAttribLatch[attrib_i + 2];
494
sprite_tile &= IsSetBit(m_VdpRegister[1], 1) ? 0xFC : 0xFF;
495
496
int sprite_line_addr = sprite_pattern_addr + (sprite_tile << 3) +
497
((line - sprite_y) >> (sprite_zoom ? 1 : 0));
498
499
for (int tile_x = 0; tile_x < sprite_size; tile_x++)
500
{
501
int sprite_pixel_x = sprite_x + tile_x;
502
503
if (sprite_pixel_x >= GC_RESOLUTION_WIDTH)
504
break;
505
if (sprite_pixel_x < 0)
506
continue;
507
508
int pixel = line_width + sprite_pixel_x;
509
510
bool sprite_pixel = false;
511
512
int tile_x_adjusted = tile_x >> (sprite_zoom ? 1 : 0);
513
514
if (tile_x_adjusted < 8)
515
sprite_pixel = IsSetBit(m_pVdpVRAM[sprite_line_addr], 7 - tile_x_adjusted);
516
else
517
sprite_pixel = IsSetBit(m_pVdpVRAM[sprite_line_addr + 16], 15 - tile_x_adjusted);
518
519
if (sprite_pixel && ((sprite_count < 5) || m_bNoSpriteLimit))
520
{
521
if (!IsSetBit(m_pInfoBuffer[pixel], 0) && (sprite_color > 0))
522
{
523
m_pFrameBuffer[pixel] = sprite_color;
524
m_pInfoBuffer[pixel] = SetBit(m_pInfoBuffer[pixel], 0);
525
}
526
527
if (IsSetBit(m_pInfoBuffer[pixel], 1))
528
{
529
m_VdpStatus = SetBit(m_VdpStatus, 5);
530
}
531
else
532
{
533
m_pInfoBuffer[pixel] = SetBit(m_pInfoBuffer[pixel], 1);
534
}
535
}
536
}
537
}
538
}
539
540
541
void Video::Render24bit(u16* srcFrameBuffer, u8* dstFrameBuffer, GC_Color_Format pixelFormat, int size, bool overscan)
542
{
543
int x = 0;
544
int y = 0;
545
int overscan_h_l = 0;
546
int overscan_v = 0;
547
int overscan_content_v = 0;
548
int overscan_content_h = 0;
549
int overscan_total_width = GC_RESOLUTION_WIDTH;
550
int overscan_total_height = 0;
551
bool overscan_enabled = false;
552
int overscan_color = (m_VdpRegister[7] & 0x0F) * 3;
553
int buffer_size = size * 3;
554
bool bgr = (pixelFormat == GC_PIXEL_BGR888);
555
556
if (overscan && (m_Overscan != OverscanDisabled))
557
{
558
overscan_enabled = true;
559
overscan_content_v = GC_RESOLUTION_HEIGHT;
560
overscan_v = m_bPAL ? GC_RESOLUTION_OVERSCAN_V_PAL : GC_RESOLUTION_OVERSCAN_V;
561
overscan_total_height = overscan_content_v + (overscan_v * 2);
562
}
563
564
if (overscan && (m_Overscan == OverscanFull320))
565
{
566
overscan_content_h = GC_RESOLUTION_WIDTH;
567
overscan_h_l = GC_RESOLUTION_SMS_OVERSCAN_H_320_L;
568
overscan_total_width = overscan_content_h + overscan_h_l + GC_RESOLUTION_SMS_OVERSCAN_H_320_R;
569
}
570
571
if (overscan && (m_Overscan == OverscanFull284))
572
{
573
overscan_content_h = GC_RESOLUTION_WIDTH;
574
overscan_h_l = GC_RESOLUTION_SMS_OVERSCAN_H_284_L;
575
overscan_total_width = overscan_content_h + overscan_h_l + GC_RESOLUTION_SMS_OVERSCAN_H_284_R;
576
}
577
578
for (int i = 0, j = 0; j < buffer_size; j += 3)
579
{
580
u16 src_color = 0;
581
if (overscan_enabled)
582
{
583
bool is_h_overscan = (overscan_h_l > 0) && (x < overscan_h_l || x >= (overscan_h_l + overscan_content_h));
584
bool is_v_overscan = (overscan_v > 0) && (y < overscan_v || y >= (overscan_v + overscan_content_v));
585
586
if (is_h_overscan || is_v_overscan)
587
src_color = overscan_color;
588
else
589
src_color = srcFrameBuffer[i++] * 3;
590
591
if (++x == overscan_total_width)
592
{
593
x = 0;
594
if (++y == overscan_total_height)
595
{
596
y = 0;
597
}
598
}
599
}
600
else
601
src_color = srcFrameBuffer[i++] * 3;
602
603
dstFrameBuffer[j + 0] = bgr ? m_pCurrentPalette[src_color + 2] : m_pCurrentPalette[src_color];
604
dstFrameBuffer[j + 1] = m_pCurrentPalette[src_color + 1];
605
dstFrameBuffer[j + 2] = bgr ? m_pCurrentPalette[src_color] : m_pCurrentPalette[src_color + 2];
606
}
607
}
608
609
void Video::Render16bit(u16* srcFrameBuffer, u8* dstFrameBuffer, GC_Color_Format pixelFormat, int size, bool overscan)
610
{
611
int x = 0;
612
int y = 0;
613
int overscan_h_l = 0;
614
int overscan_v = 0;
615
int overscan_content_v = 0;
616
int overscan_content_h = 0;
617
int overscan_total_width = GC_RESOLUTION_WIDTH;
618
int overscan_total_height = 0;
619
bool overscan_enabled = false;
620
int overscan_color = m_VdpRegister[7] & 0x0F;
621
int buffer_size = size * 2;
622
bool bgr = ((pixelFormat == GC_PIXEL_BGR555) || (pixelFormat == GC_PIXEL_BGR565));
623
bool green_6bit = (pixelFormat == GC_PIXEL_RGB565) || (pixelFormat == GC_PIXEL_BGR565);
624
const u16* pal;
625
626
if (bgr)
627
pal = green_6bit ? m_palette_565_bgr : m_palette_555_bgr;
628
else
629
pal = green_6bit ? m_palette_565_rgb : m_palette_555_rgb;
630
631
if (overscan && (m_Overscan != OverscanDisabled))
632
{
633
overscan_enabled = true;
634
overscan_content_v = GC_RESOLUTION_HEIGHT;
635
overscan_v = m_bPAL ? GC_RESOLUTION_OVERSCAN_V_PAL : GC_RESOLUTION_OVERSCAN_V;
636
overscan_total_height = overscan_content_v + (overscan_v * 2);
637
}
638
639
if (overscan && (m_Overscan == OverscanFull320))
640
{
641
overscan_content_h = GC_RESOLUTION_WIDTH;
642
overscan_h_l = GC_RESOLUTION_SMS_OVERSCAN_H_320_L;
643
overscan_total_width = overscan_content_h + overscan_h_l + GC_RESOLUTION_SMS_OVERSCAN_H_320_R;
644
}
645
646
if (overscan && (m_Overscan == OverscanFull284))
647
{
648
overscan_content_h = GC_RESOLUTION_WIDTH;
649
overscan_h_l = GC_RESOLUTION_SMS_OVERSCAN_H_284_L;
650
overscan_total_width = overscan_content_h + overscan_h_l + GC_RESOLUTION_SMS_OVERSCAN_H_284_R;
651
}
652
653
for (int i = 0, j = 0; j < buffer_size; j += 2)
654
{
655
u16 src_color = 0;
656
if (overscan_enabled)
657
{
658
bool is_h_overscan = (overscan_h_l > 0) && (x < overscan_h_l || x >= (overscan_h_l + overscan_content_h));
659
bool is_v_overscan = (overscan_v > 0) && (y < overscan_v || y >= (overscan_v + overscan_content_v));
660
661
if (is_h_overscan || is_v_overscan)
662
src_color = overscan_color;
663
else
664
src_color = srcFrameBuffer[i++];
665
666
if (++x == overscan_total_width)
667
{
668
x = 0;
669
if (++y == overscan_total_height)
670
{
671
y = 0;
672
}
673
}
674
}
675
else
676
src_color = srcFrameBuffer[i++];
677
678
*(u16*)(&dstFrameBuffer[j]) = pal[src_color];
679
}
680
}
681
682
void Video::SetCustomPalette(GC_Color* palette)
683
{
684
for (int i = 0; i < 16; i++)
685
{
686
int p = i * 3;
687
m_CustomPalette[p] = palette[i].red;
688
m_CustomPalette[p + 1] = palette[i].green;
689
m_CustomPalette[p + 2] = palette[i].blue;
690
}
691
692
m_pCurrentPalette = m_CustomPalette;
693
InitPalettes();
694
}
695
696
void Video::SetPredefinedPalette(int palette)
697
{
698
const u8* predefined;
699
700
switch (palette)
701
{
702
case 0:
703
predefined = kPalette_888_coleco;
704
break;
705
case 1:
706
predefined = kPalette_888_tms9918;
707
break;
708
default:
709
predefined = NULL;
710
}
711
712
if (IsValidPointer(predefined))
713
{
714
m_pCurrentPalette = const_cast<u8*>(predefined);
715
InitPalettes();
716
}
717
}
718
719
void Video::InitPalettes()
720
{
721
for (int i=0,j=0; i<16; i++,j+=3)
722
{
723
u8 red = m_pCurrentPalette[j];
724
u8 green = m_pCurrentPalette[j+1];
725
u8 blue = m_pCurrentPalette[j+2];
726
727
u8 red_5 = red * 31 / 255;
728
u8 green_5 = green * 31 / 255;
729
u8 green_6 = green * 63 / 255;
730
u8 blue_5 = blue * 31 / 255;
731
732
m_palette_565_rgb[i] = red_5 << 11 | green_6 << 5 | blue_5;
733
m_palette_555_rgb[i] = red_5 << 10 | green_5 << 5 | blue_5;
734
m_palette_565_bgr[i] = blue_5 << 11 | green_6 << 5 | red_5;
735
m_palette_555_bgr[i] = blue_5 << 10 | green_5 << 5 | red_5;
736
}
737
}
738
739
void Video::SetOverscan(Overscan overscan)
740
{
741
m_Overscan = overscan;
742
}
743
744
Video::Overscan Video::GetOverscan()
745
{
746
return m_Overscan;
747
}
748
749
void Video::SaveState(std::ostream& stream)
750
{
751
stream.write(reinterpret_cast<const char*> (m_pInfoBuffer), GC_RESOLUTION_WIDTH * GC_LINES_PER_FRAME_PAL);
752
stream.write(reinterpret_cast<const char*> (m_pVdpVRAM), 0x4000);
753
stream.write(reinterpret_cast<const char*> (&m_bFirstByteInSequence), sizeof(m_bFirstByteInSequence));
754
stream.write(reinterpret_cast<const char*> (m_VdpRegister), sizeof(m_VdpRegister));
755
stream.write(reinterpret_cast<const char*> (&m_VdpBuffer), sizeof(m_VdpBuffer));
756
stream.write(reinterpret_cast<const char*> (&m_VdpAddress), sizeof(m_VdpAddress));
757
stream.write(reinterpret_cast<const char*> (&m_iCycleCounter), sizeof(m_iCycleCounter));
758
stream.write(reinterpret_cast<const char*> (&m_VdpStatus), sizeof(m_VdpStatus));
759
stream.write(reinterpret_cast<const char*> (&m_iLinesPerFrame), sizeof(m_iLinesPerFrame));
760
stream.write(reinterpret_cast<const char*> (&m_LineEvents), sizeof(m_LineEvents));
761
stream.write(reinterpret_cast<const char*> (&m_iRenderLine), sizeof(m_iRenderLine));
762
stream.write(reinterpret_cast<const char*> (&m_bPAL), sizeof(m_bPAL));
763
stream.write(reinterpret_cast<const char*> (&m_iMode), sizeof(m_iMode));
764
stream.write(reinterpret_cast<const char*> (&m_Timing), sizeof(m_Timing));
765
stream.write(reinterpret_cast<const char*> (&m_bDisplayEnabled), sizeof(m_bDisplayEnabled));
766
stream.write(reinterpret_cast<const char*> (&m_bSpriteOvrRequest), sizeof(m_bSpriteOvrRequest));
767
}
768
769
void Video::LoadState(std::istream& stream)
770
{
771
stream.read(reinterpret_cast<char*> (m_pInfoBuffer), GC_RESOLUTION_WIDTH * GC_LINES_PER_FRAME_PAL);
772
stream.read(reinterpret_cast<char*> (m_pVdpVRAM), 0x4000);
773
stream.read(reinterpret_cast<char*> (&m_bFirstByteInSequence), sizeof(m_bFirstByteInSequence));
774
stream.read(reinterpret_cast<char*> (m_VdpRegister), sizeof(m_VdpRegister));
775
stream.read(reinterpret_cast<char*> (&m_VdpBuffer), sizeof(m_VdpBuffer));
776
stream.read(reinterpret_cast<char*> (&m_VdpAddress), sizeof(m_VdpAddress));
777
stream.read(reinterpret_cast<char*> (&m_iCycleCounter), sizeof(m_iCycleCounter));
778
stream.read(reinterpret_cast<char*> (&m_VdpStatus), sizeof(m_VdpStatus));
779
stream.read(reinterpret_cast<char*> (&m_iLinesPerFrame), sizeof(m_iLinesPerFrame));
780
stream.read(reinterpret_cast<char*> (&m_LineEvents), sizeof(m_LineEvents));
781
stream.read(reinterpret_cast<char*> (&m_iRenderLine), sizeof(m_iRenderLine));
782
stream.read(reinterpret_cast<char*> (&m_bPAL), sizeof(m_bPAL));
783
stream.read(reinterpret_cast<char*> (&m_iMode), sizeof(m_iMode));
784
stream.read(reinterpret_cast<char*> (&m_Timing), sizeof(m_Timing));
785
stream.read(reinterpret_cast<char*> (&m_bDisplayEnabled), sizeof(m_bDisplayEnabled));
786
stream.read(reinterpret_cast<char*> (&m_bSpriteOvrRequest), sizeof(m_bSpriteOvrRequest));
787
}
788
789