trunk/src/mame/video/hng64_3d.c
| r249156 | r249157 | |
| 1 | 1 | // license:LGPL-2.1+ |
| 2 | 2 | // copyright-holders:David Haywood, Angelo Salese, ElSemi, Andrew Gardner, Andrew Zaferakis |
| 3 | | /* Hyper NeoGeo 64 - 3D bits */ |
| 4 | 3 | |
| 5 | | // todo, use poly.c |
| 6 | | |
| 7 | 4 | #include "includes/hng64.h" |
| 8 | 5 | |
| 6 | ///////////////////////////////// |
| 7 | /// Hyper NeoGeo 64 - 3D bits /// |
| 8 | ///////////////////////////////// |
| 9 | 9 | |
| 10 | 10 | |
| 11 | // Polygon rasterizer interface |
| 12 | hng64_poly_renderer::hng64_poly_renderer(hng64_state& state) |
| 13 | : poly_manager<float, hng64_poly_data, 7, HNG64_MAX_POLYGONS>(state.machine()) |
| 14 | , m_state(state) |
| 15 | , m_colorBuffer3d(state.m_screen->visible_area().width(), state.m_screen->visible_area().height()) |
| 16 | { |
| 17 | const INT32 bufferSize = state.m_screen->visible_area().width() * state.m_screen->visible_area().height(); |
| 18 | m_depthBuffer3d = auto_alloc_array(state.machine(), float, bufferSize); |
| 19 | } |
| 20 | |
| 21 | |
| 22 | |
| 11 | 23 | // Hardware calls these '3d buffers' |
| 12 | 24 | // They're only read during the startup check of fatfurwa. Z-buffer memory? Front buffer, back buffer? |
| 13 | 25 | // They're definitely mirrored in the startup test, according to ElSemi |
| r249156 | r249157 | |
| 54 | 66 | for(int packetStart=0;packetStart<0x200;packetStart+=32) |
| 55 | 67 | { |
| 56 | 68 | // Send it off to the 3d subsystem. |
| 57 | | hng64_command3d( &m_dl[packetStart/2] ); |
| 69 | hng64_command3d(&m_dl[packetStart/2]); |
| 58 | 70 | } |
| 59 | 71 | |
| 60 | 72 | machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(0x200*8), timer_expired_delegate(FUNC(hng64_state::hng64_3dfifo_processed),this)); |
| 61 | 73 | g_profiler.stop(); |
| 62 | 74 | } |
| 63 | 75 | |
| 64 | | TIMER_CALLBACK_MEMBER(hng64_state::hng64_3dfifo_processed ) |
| 76 | TIMER_CALLBACK_MEMBER(hng64_state::hng64_3dfifo_processed) |
| 65 | 77 | { |
| 66 | 78 | // ... |
| 67 | 79 | m_set_irq(0x0008); |
| r249156 | r249157 | |
| 584 | 596 | polys[*numPolys].vert[m].texCoords[3] = 1.0f; |
| 585 | 597 | |
| 586 | 598 | polys[*numPolys].vert[m].normal[0] = uToF(chunkOffset[9 + (9*m)]); |
| 587 | | polys[*numPolys].vert[m].normal[1] = uToF(chunkOffset[10 + (9*m)] ); |
| 588 | | polys[*numPolys].vert[m].normal[2] = uToF(chunkOffset[11 + (9*m)] ); |
| 599 | polys[*numPolys].vert[m].normal[1] = uToF(chunkOffset[10 + (9*m)]); |
| 600 | polys[*numPolys].vert[m].normal[2] = uToF(chunkOffset[11 + (9*m)]); |
| 589 | 601 | polys[*numPolys].vert[m].normal[3] = 0.0f; |
| 590 | 602 | } |
| 591 | 603 | |
| r249156 | r249157 | |
| 900 | 912 | if (packet[2] == 0x0003 && packet[3] == 0x8f37 && m_mcu_type == SHOOT_MCU) |
| 901 | 913 | break; |
| 902 | 914 | |
| 903 | | recoverPolygonBlock( packet, &numPolys); |
| 915 | recoverPolygonBlock(packet, &numPolys); |
| 904 | 916 | break; |
| 905 | 917 | |
| 906 | 918 | case 0x0102: // Geometry with only translation |
| r249156 | r249157 | |
| 920 | 932 | miniPacket[7] = 0x7fff; |
| 921 | 933 | miniPacket[11] = 0x7fff; |
| 922 | 934 | miniPacket[15] = 0x7fff; |
| 923 | | recoverPolygonBlock( miniPacket, &numPolys); |
| 935 | recoverPolygonBlock(miniPacket, &numPolys); |
| 924 | 936 | |
| 925 | 937 | memset(miniPacket, 0, sizeof(UINT16)*16); |
| 926 | 938 | for (int i = 0; i < 7; i++) miniPacket[i] = packet[i+8]; |
| r249156 | r249157 | |
| 928 | 940 | miniPacket[7] = 0x7fff; |
| 929 | 941 | miniPacket[11] = 0x7fff; |
| 930 | 942 | miniPacket[15] = 0x7fff; |
| 931 | | recoverPolygonBlock( miniPacket, &numPolys); |
| 943 | recoverPolygonBlock(miniPacket, &numPolys); |
| 932 | 944 | break; |
| 933 | 945 | |
| 934 | 946 | case 0x1000: // Unknown: Some sort of global flags? |
| r249156 | r249157 | |
| 949 | 961 | { |
| 950 | 962 | if (polys[i].visible) |
| 951 | 963 | { |
| 952 | | drawShaded( &polys[i]); |
| 964 | m_poly_renderer->drawShaded(&polys[i]); |
| 953 | 965 | } |
| 954 | 966 | } |
| 967 | m_poly_renderer->wait(); |
| 955 | 968 | } |
| 956 | 969 | |
| 957 | 970 | void hng64_state::clear3d() |
| r249156 | r249157 | |
| 963 | 976 | // Reset the buffers... |
| 964 | 977 | for (i = 0; i < (visarea.max_x)*(visarea.max_y); i++) |
| 965 | 978 | { |
| 966 | | m_depthBuffer3d[i] = 100.0f; |
| 967 | | m_colorBuffer3d[i] = rgb_t(0, 0, 0, 0); |
| 979 | m_poly_renderer->depthBuffer3d()[i] = 100.0f; |
| 968 | 980 | } |
| 981 | |
| 982 | // Clear the 3d rasterizer buffer |
| 983 | m_poly_renderer->colorBuffer3d().fill(0x00000000, m_screen->visible_area()); |
| 969 | 984 | |
| 970 | 985 | // Set some matrices to the identity... |
| 971 | 986 | setIdentity(m_projectionMatrix); |
| r249156 | r249157 | |
| 994 | 1009 | ///////////////////// |
| 995 | 1010 | |
| 996 | 1011 | /* 4x4 matrix multiplication */ |
| 997 | | void hng64_state::matmul4(float *product, const float *a, const float *b ) |
| 1012 | void hng64_state::matmul4(float *product, const float *a, const float *b) |
| 998 | 1013 | { |
| 999 | 1014 | int i; |
| 1000 | 1015 | for (i = 0; i < 4; i++) |
| r249156 | r249157 | |
| 1072 | 1087 | // POLYGON CLIPPING CODE // |
| 1073 | 1088 | /////////////////////////// |
| 1074 | 1089 | |
| 1075 | | /////////////////////////////////////////////////////////////////////////////////// |
| 1076 | | // The remainder of the code in this file is heavily // |
| 1077 | | // influenced by, and sometimes copied verbatim from Andrew Zaferakis' SoftGL // |
| 1078 | | // rasterizing system. // |
| 1079 | | // // |
| 1080 | | // Andrew granted permission for its use in MAME in October of 2004. // |
| 1081 | | /////////////////////////////////////////////////////////////////////////////////// |
| 1082 | | |
| 1083 | | |
| 1084 | | |
| 1085 | 1090 | int hng64_state::Inside(struct polyVert *v, int plane) |
| 1086 | 1091 | { |
| 1087 | 1092 | switch(plane) |
| r249156 | r249157 | |
| 1158 | 1163 | Ol[2] = Il0[2] + (Il1[2] - Il0[2]) * t; |
| 1159 | 1164 | } |
| 1160 | 1165 | |
| 1166 | ////////////////////////////////////////////////////////////////////////// |
| 1167 | // Clip against the volumes defined by the homogeneous clip coordinates // |
| 1168 | ////////////////////////////////////////////////////////////////////////// |
| 1169 | |
| 1161 | 1170 | void hng64_state::performFrustumClip(struct polygon *p) |
| 1162 | 1171 | { |
| 1163 | | int i, j, k; |
| 1164 | | ////////////////////////////////////////////////////////////////////////// |
| 1165 | | // Clip against the volumes defined by the homogeneous clip coordinates // |
| 1166 | | ////////////////////////////////////////////////////////////////////////// |
| 1172 | polyVert *v0; |
| 1173 | polyVert *v1; |
| 1174 | polyVert *tv; |
| 1167 | 1175 | |
| 1168 | | struct polygon temp; |
| 1169 | | |
| 1170 | | struct polyVert *v0; |
| 1171 | | struct polyVert *v1; |
| 1172 | | struct polyVert *tv; |
| 1173 | | |
| 1176 | polygon temp; |
| 1174 | 1177 | temp.n = 0; |
| 1175 | 1178 | |
| 1176 | 1179 | // Skip near and far clipping planes ? |
| 1177 | | for (j = 0; j <= HNG64_BOTTOM; j++) |
| 1180 | for (int j = 0; j <= HNG64_BOTTOM; j++) |
| 1178 | 1181 | { |
| 1179 | | for (i = 0; i < p->n; i++) |
| 1182 | for (int i = 0; i < p->n; i++) |
| 1180 | 1183 | { |
| 1181 | | k = (i+1) % p->n; // Index of next vertex |
| 1184 | int k = (i+1) % p->n; // Index of next vertex |
| 1182 | 1185 | |
| 1183 | 1186 | v0 = &p->vert[i]; |
| 1184 | 1187 | v1 = &p->vert[k]; |
| r249156 | r249157 | |
| 1190 | 1193 | memcpy(tv, v1, sizeof(struct polyVert)); |
| 1191 | 1194 | temp.n++; |
| 1192 | 1195 | } |
| 1193 | | |
| 1194 | 1196 | else if (Inside(v0, j) && !Inside(v1, j)) // Edge goes from in to out... |
| 1195 | 1197 | { |
| 1196 | 1198 | Intersect(v0, v1, tv, j); |
| 1197 | 1199 | temp.n++; |
| 1198 | 1200 | } |
| 1199 | | |
| 1200 | 1201 | else if (!Inside(v0, j) && Inside(v1, j)) // Edge goes from out to in... |
| 1201 | 1202 | { |
| 1202 | 1203 | Intersect(v0, v1, tv, j); |
| r249156 | r249157 | |
| 1207 | 1208 | |
| 1208 | 1209 | p->n = temp.n; |
| 1209 | 1210 | |
| 1210 | | for (i = 0; i < temp.n; i++) |
| 1211 | for (int i = 0; i < temp.n; i++) |
| 1211 | 1212 | { |
| 1212 | 1213 | memcpy(&p->vert[i], &temp.vert[i], sizeof(struct polyVert)); |
| 1213 | 1214 | } |
| r249156 | r249157 | |
| 1216 | 1217 | } |
| 1217 | 1218 | } |
| 1218 | 1219 | |
| 1219 | | |
| 1220 | | |
| 1221 | | /*********************************************************************/ |
| 1222 | | /** FillSmoothTexPCHorizontalLine **/ |
| 1223 | | /** Input: Color Buffer (framebuffer), depth buffer, width and **/ |
| 1224 | | /** height of framebuffer, starting, and ending values **/ |
| 1225 | | /** for x and y, constant y. Fills horizontally with **/ |
| 1226 | | /** z,r,g,b interpolation. **/ |
| 1227 | | /** **/ |
| 1228 | | /** Output: none **/ |
| 1229 | | /*********************************************************************/ |
| 1230 | | inline void hng64_state::FillSmoothTexPCHorizontalLine( |
| 1231 | | const polygonRasterOptions& prOptions, |
| 1232 | | int x_start, int x_end, int y, float z_start, float z_delta, |
| 1233 | | float w_start, float w_delta, float r_start, float r_delta, |
| 1234 | | float g_start, float g_delta, float b_start, float b_delta, |
| 1235 | | float s_start, float s_delta, float t_start, float t_delta) |
| 1220 | void hng64_poly_renderer::render_scanline(INT32 scanline, const extent_t& extent, const hng64_poly_data& renderData, int threadid) |
| 1236 | 1221 | { |
| 1237 | | float* db = &(m_depthBuffer3d[(y * m_screen->visible_area().max_x) + x_start]); |
| 1238 | | UINT32* cb = &(m_colorBuffer3d[(y * m_screen->visible_area().max_x) + x_start]); |
| 1222 | // Pull the parameters out of the extent structure |
| 1223 | float z = extent.param[0].start; |
| 1224 | float w = extent.param[1].start; |
| 1225 | float lightR = extent.param[2].start; |
| 1226 | float lightG = extent.param[3].start; |
| 1227 | float lightB = extent.param[4].start; |
| 1228 | float s = extent.param[5].start; |
| 1229 | float t = extent.param[6].start; |
| 1230 | |
| 1231 | const float dz = extent.param[0].dpdx; |
| 1232 | const float dw = extent.param[1].dpdx; |
| 1233 | const float dlightR = extent.param[2].dpdx; |
| 1234 | const float dlightG = extent.param[3].dpdx; |
| 1235 | const float dlightB = extent.param[4].dpdx; |
| 1236 | const float ds = extent.param[5].dpdx; |
| 1237 | const float dt = extent.param[6].dpdx; |
| 1238 | |
| 1239 | // Pointers to the pixel buffers |
| 1240 | UINT32* colorBuffer = &m_colorBuffer3d.pix32(scanline, extent.startx); |
| 1241 | float* depthBuffer = &m_depthBuffer3d[(scanline * m_state.m_screen->visible_area().width()) + extent.startx]; |
| 1239 | 1242 | |
| 1240 | | UINT8 paletteEntry = 0; |
| 1241 | | float t_coord, s_coord; |
| 1242 | | const UINT8 *gfx = m_texturerom; |
| 1243 | | const UINT8 *textureOffset = &gfx[prOptions.texIndex * 1024 * 1024]; |
| 1243 | const UINT8 *textureOffset = &m_state.m_texturerom[renderData.texIndex * 1024 * 1024]; |
| 1244 | |
| 1245 | // Step over each pixel in the horizontal span |
| 1246 | for(int x = extent.startx; x < extent.stopx; x++) |
| 1247 | { |
| 1248 | if (z < *depthBuffer) |
| 1249 | { |
| 1250 | // Translucency currently isn't an issue, so soldier on |
| 1251 | *depthBuffer = z; |
| 1244 | 1252 | |
| 1245 | | for (; x_start <= x_end; x_start++) |
| 1246 | | { |
| 1247 | | if (z_start < (*db)) |
| 1248 | | { |
| 1249 | | // MULTIPLY BACK THROUGH BY W |
| 1250 | | t_coord = t_start / w_start; |
| 1251 | | s_coord = s_start / w_start; |
| 1252 | | |
| 1253 | | if ((prOptions.debugColor & 0xff000000) == 0x01000000) |
| 1253 | // Multiply back through by w for everything that was interpolated perspective-correctly |
| 1254 | const float sCorrect = s / w; |
| 1255 | const float tCorrect = t / w; |
| 1256 | const float rCorrect = lightR / w; |
| 1257 | const float gCorrect = lightG / w; |
| 1258 | const float bCorrect = lightB / w; |
| 1259 | |
| 1260 | if ((renderData.debugColor & 0xff000000) == 0x01000000) |
| 1254 | 1261 | { |
| 1255 | | // UV COLOR MODE |
| 1256 | | *cb = rgb_t(255, (UINT8)(s_coord*255.0f), (UINT8)(t_coord*255.0f), (UINT8)(0)); |
| 1257 | | *db = z_start; |
| 1262 | // ST color mode |
| 1263 | *colorBuffer = rgb_t(255, (UINT8)(sCorrect*255.0f), (UINT8)(tCorrect*255.0f), (UINT8)(0)); |
| 1258 | 1264 | } |
| 1259 | | else if ((prOptions.debugColor & 0xff000000) == 0x02000000) |
| 1265 | else if ((renderData.debugColor & 0xff000000) == 0x02000000) |
| 1260 | 1266 | { |
| 1261 | | // Lit |
| 1262 | | *cb = rgb_t(255, (UINT8)(r_start/w_start), (UINT8)(g_start/w_start), (UINT8)(b_start/w_start)); |
| 1263 | | *db = z_start; |
| 1267 | // Lighting only |
| 1268 | *colorBuffer = rgb_t(255, (UINT8)rCorrect, (UINT8)gCorrect, (UINT8)bCorrect); |
| 1264 | 1269 | } |
| 1265 | | else if ((prOptions.debugColor & 0xff000000) == 0xff000000) |
| 1270 | else if ((renderData.debugColor & 0xff000000) == 0xff000000) |
| 1266 | 1271 | { |
| 1267 | | // DEBUG COLOR MODE |
| 1268 | | *cb = prOptions.debugColor; |
| 1269 | | *db = z_start; |
| 1272 | // Debug color mode |
| 1273 | *colorBuffer = renderData.debugColor; |
| 1270 | 1274 | } |
| 1271 | 1275 | else |
| 1272 | 1276 | { |
| r249156 | r249157 | |
| 1274 | 1278 | float textureT = 0.0f; |
| 1275 | 1279 | |
| 1276 | 1280 | // Standard & Half-Res textures |
| 1277 | | if (prOptions.texType == 0x0) |
| 1281 | if (renderData.texType == 0x0) |
| 1278 | 1282 | { |
| 1279 | | textureS = s_coord * 1024.0f; |
| 1280 | | textureT = t_coord * 1024.0f; |
| 1283 | textureS = sCorrect * 1024.0f; |
| 1284 | textureT = tCorrect * 1024.0f; |
| 1281 | 1285 | } |
| 1282 | | else if (prOptions.texType == 0x1) |
| 1286 | else if (renderData.texType == 0x1) |
| 1283 | 1287 | { |
| 1284 | | textureS = s_coord * 512.0f; |
| 1285 | | textureT = t_coord * 512.0f; |
| 1288 | textureS = sCorrect * 512.0f; |
| 1289 | textureT = tCorrect * 512.0f; |
| 1286 | 1290 | } |
| 1287 | 1291 | |
| 1288 | | // stuff in mode 1 here already looks good? |
| 1289 | 1292 | // Small-Page textures |
| 1290 | | if (prOptions.texPageSmall == 2) |
| 1293 | if (renderData.texPageSmall == 2) |
| 1291 | 1294 | { |
| 1292 | 1295 | textureT = fmod(textureT, 256.0f); |
| 1293 | 1296 | textureS = fmod(textureS, 256.0f); |
| 1294 | 1297 | |
| 1295 | | textureT += (256.0f * (prOptions.texPageHorizOffset>>1)); |
| 1296 | | textureS += (256.0f * (prOptions.texPageVertOffset>>1)); |
| 1298 | textureT += (256.0f * (renderData.texPageHorizOffset>>1)); |
| 1299 | textureS += (256.0f * (renderData.texPageVertOffset>>1)); |
| 1297 | 1300 | } |
| 1298 | | else if (prOptions.texPageSmall == 3) |
| 1301 | else if (renderData.texPageSmall == 3) |
| 1299 | 1302 | { |
| 1300 | 1303 | textureT = fmod(textureT, 128.0f); |
| 1301 | 1304 | textureS = fmod(textureS, 128.0f); |
| 1302 | 1305 | |
| 1303 | | textureT += (128.0f * (prOptions.texPageHorizOffset>>0)); |
| 1304 | | textureS += (128.0f * (prOptions.texPageVertOffset>>0)); |
| 1306 | textureT += (128.0f * (renderData.texPageHorizOffset>>0)); |
| 1307 | textureS += (128.0f * (renderData.texPageVertOffset>>0)); |
| 1305 | 1308 | } |
| 1306 | 1309 | |
| 1307 | | paletteEntry = textureOffset[((int)textureS)*1024 + (int)textureT]; |
| 1310 | UINT8 paletteEntry = textureOffset[((int)textureS)*1024 + (int)textureT]; |
| 1308 | 1311 | |
| 1309 | | // Naieve Alpha Implementation (?) - don't draw if you're at texture index 0... |
| 1312 | // Naive Alpha Implementation (?) - don't draw if you're at texture index 0... |
| 1310 | 1313 | if (paletteEntry != 0) |
| 1311 | 1314 | { |
| 1312 | 1315 | // The color out of the texture |
| 1313 | | paletteEntry %= prOptions.palPageSize; |
| 1314 | | rgb_t color = m_palette->pen(prOptions.palOffset + paletteEntry); |
| 1316 | paletteEntry %= renderData.palPageSize; |
| 1317 | rgb_t color = m_state.m_palette->pen(renderData.palOffset + paletteEntry); |
| 1315 | 1318 | |
| 1316 | 1319 | // Apply the lighting |
| 1317 | | float rIntensity = (r_start/w_start) / 255.0f; |
| 1318 | | float gIntensity = (g_start/w_start) / 255.0f; |
| 1319 | | float bIntensity = (b_start/w_start) / 255.0f; |
| 1320 | | float red = color.r() * rIntensity; |
| 1320 | float rIntensity = rCorrect / 255.0f; |
| 1321 | float gIntensity = gCorrect / 255.0f; |
| 1322 | float bIntensity = bCorrect / 255.0f; |
| 1323 | float red = color.r() * rIntensity; |
| 1321 | 1324 | float green = color.g() * gIntensity; |
| 1322 | | float blue = color.b() * bIntensity; |
| 1325 | float blue = color.b() * bIntensity; |
| 1323 | 1326 | |
| 1324 | 1327 | // Clamp and finalize |
| 1325 | 1328 | red = color.r() + red; |
| r249156 | r249157 | |
| 1332 | 1335 | |
| 1333 | 1336 | color = rgb_t(255, (UINT8)red, (UINT8)green, (UINT8)blue); |
| 1334 | 1337 | |
| 1335 | | *cb = color; |
| 1336 | | *db = z_start; |
| 1338 | *colorBuffer = color; |
| 1337 | 1339 | } |
| 1338 | 1340 | } |
| 1339 | | } |
| 1340 | | db++; |
| 1341 | | cb++; |
| 1342 | | z_start += z_delta; |
| 1343 | | w_start += w_delta; |
| 1344 | | r_start += r_delta; |
| 1345 | | g_start += g_delta; |
| 1346 | | b_start += b_delta; |
| 1347 | | s_start += s_delta; |
| 1348 | | t_start += t_delta; |
| 1349 | | } |
| 1350 | | } |
| 1341 | } |
| 1351 | 1342 | |
| 1352 | | //---------------------------------------------------------------------------- |
| 1353 | | // Given 3D triangle ABC in screen space with clipped coordinates within the following |
| 1354 | | // bounds: x in [0,W], y in [0,H], z in [0,1]. The origin for (x,y) is in the bottom |
| 1355 | | // left corner of the pixel grid. z=0 is the near plane and z=1 is the far plane, |
| 1356 | | // so lesser values are closer. The coordinates of the pixels are evenly spaced |
| 1357 | | // in x and y 1 units apart starting at the bottom-left pixel with coords |
| 1358 | | // (0.5,0.5). In other words, the pixel sample point is in the center of the |
| 1359 | | // rectangular grid cell containing the pixel sample. The framebuffer has |
| 1360 | | // dimensions width x height (WxH). The Color buffer is a 1D array (row-major |
| 1361 | | // order) with 3 unsigned chars per pixel (24-bit color). The Depth buffer is |
| 1362 | | // a 1D array (also row-major order) with a float value per pixel |
| 1363 | | // For a pixel location (x,y) we can obtain |
| 1364 | | // the Color and Depth array locations as: Color[(((int)y)*W+((int)x))*3] |
| 1365 | | // (for the red value, green is offset +1, and blue is offset +2 and |
| 1366 | | // Depth[((int)y)*W+((int)x)]. Fills the pixels contained in the triangle |
| 1367 | | // with the global current color and the properly linearly interpolated depth |
| 1368 | | // value (performs Z-buffer depth test before writing new pixel). |
| 1369 | | // Pixel samples that lie inside the triangle edges are filled with |
| 1370 | | // a bias towards the minimum values (samples that lie exactly on a triangle |
| 1371 | | // edge are filled only for minimum x values along a horizontal span and for |
| 1372 | | // minimum y values, samples lying on max values are not filled). |
| 1373 | | // Per-vertex colors are RGB floating point triplets in [0.0,255.0]. The vertices |
| 1374 | | // include their w-components for use in linearly interpolating perspectively |
| 1375 | | // correct color (RGB) and texture-coords (st) across the face of the triangle. |
| 1376 | | // A texture image of RGB floating point triplets of size TWxWH is also given. |
| 1377 | | // Texture colors are normalized RGB values in [0,1]. |
| 1378 | | // clamp and repeat wrapping modes : Wrapping={0,1} |
| 1379 | | // nearest and bilinear filtering: Filtering={0,1} |
| 1380 | | // replace and modulate application modes: Function={0,1} |
| 1381 | | //--------------------------------------------------------------------------- |
| 1382 | | void hng64_state::RasterizeTriangle_SMOOTH_TEX_PC( |
| 1383 | | float A[4], float B[4], float C[4], |
| 1384 | | float Ca[3], float Cb[3], float Cc[3], // PER-VERTEX RGB COLORS |
| 1385 | | float Ta[2], float Tb[2], float Tc[2], // PER-VERTEX (S,T) TEX-COORDS |
| 1386 | | const polygonRasterOptions& prOptions) |
| 1387 | | { |
| 1388 | | // Get our order of points by increasing y-coord |
| 1389 | | float *p_min = ((A[1] <= B[1]) && (A[1] <= C[1])) ? A : ((B[1] <= A[1]) && (B[1] <= C[1])) ? B : C; |
| 1390 | | float *p_max = ((A[1] >= B[1]) && (A[1] >= C[1])) ? A : ((B[1] >= A[1]) && (B[1] >= C[1])) ? B : C; |
| 1391 | | float *p_mid = ((A != p_min) && (A != p_max)) ? A : ((B != p_min) && (B != p_max)) ? B : C; |
| 1392 | | |
| 1393 | | // Perspectively correct color interpolation, interpolate r/w, g/w, b/w, then divide by 1/w at each pixel (A[3] = 1/w) |
| 1394 | | float ca[3], cb[3], cc[3]; |
| 1395 | | float ta[2], tb[2], tc[2]; |
| 1396 | | |
| 1397 | | float *c_min; |
| 1398 | | float *c_mid; |
| 1399 | | float *c_max; |
| 1400 | | |
| 1401 | | // We must keep the tex coords straight with the point ordering |
| 1402 | | float *t_min; |
| 1403 | | float *t_mid; |
| 1404 | | float *t_max; |
| 1405 | | |
| 1406 | | // Find out control points for y, this divides the triangle into upper and lower |
| 1407 | | int y_min; |
| 1408 | | int y_max; |
| 1409 | | int y_mid; |
| 1410 | | |
| 1411 | | // Compute the slopes of each line, and color this is used to determine the interpolation |
| 1412 | | float x1_slope; |
| 1413 | | float x2_slope; |
| 1414 | | float z1_slope; |
| 1415 | | float z2_slope; |
| 1416 | | float w1_slope; |
| 1417 | | float w2_slope; |
| 1418 | | float r1_slope; |
| 1419 | | float r2_slope; |
| 1420 | | float g1_slope; |
| 1421 | | float g2_slope; |
| 1422 | | float b1_slope; |
| 1423 | | float b2_slope; |
| 1424 | | float s1_slope; |
| 1425 | | float s2_slope; |
| 1426 | | float t1_slope; |
| 1427 | | float t2_slope; |
| 1428 | | |
| 1429 | | // Compute the t values used in the equation Ax = Ax + (Bx - Ax)*t |
| 1430 | | // We only need one t, because it is only used to compute the start. |
| 1431 | | // Create storage for the interpolated x and z values for both lines |
| 1432 | | // also for the RGB interpolation |
| 1433 | | float t; |
| 1434 | | float x1_interp; |
| 1435 | | float z1_interp; |
| 1436 | | float w1_interp; |
| 1437 | | float r1_interp; |
| 1438 | | float g1_interp; |
| 1439 | | float b1_interp; |
| 1440 | | float s1_interp; |
| 1441 | | float t1_interp; |
| 1442 | | |
| 1443 | | float x2_interp; |
| 1444 | | float z2_interp; |
| 1445 | | float w2_interp; |
| 1446 | | float r2_interp; |
| 1447 | | float g2_interp; |
| 1448 | | float b2_interp; |
| 1449 | | float s2_interp; |
| 1450 | | float t2_interp; |
| 1451 | | |
| 1452 | | // Create storage for the horizontal interpolation of z and RGB color and its starting points |
| 1453 | | // This is used to fill the triangle horizontally |
| 1454 | | int x_start, x_end; |
| 1455 | | float z_interp_x, z_delta_x; |
| 1456 | | float w_interp_x, w_delta_x; |
| 1457 | | float r_interp_x, r_delta_x; |
| 1458 | | float g_interp_x, g_delta_x; |
| 1459 | | float b_interp_x, b_delta_x; |
| 1460 | | float s_interp_x, s_delta_x; |
| 1461 | | float t_interp_x, t_delta_x; |
| 1462 | | |
| 1463 | | ca[0] = Ca[0]; ca[1] = Ca[1]; ca[2] = Ca[2]; |
| 1464 | | cb[0] = Cb[0]; cb[1] = Cb[1]; cb[2] = Cb[2]; |
| 1465 | | cc[0] = Cc[0]; cc[1] = Cc[1]; cc[2] = Cc[2]; |
| 1466 | | |
| 1467 | | // Perspectively correct tex interpolation, interpolate s/w, t/w, then divide by 1/w at each pixel (A[3] = 1/w) |
| 1468 | | ta[0] = Ta[0]; ta[1] = Ta[1]; |
| 1469 | | tb[0] = Tb[0]; tb[1] = Tb[1]; |
| 1470 | | tc[0] = Tc[0]; tc[1] = Tc[1]; |
| 1471 | | |
| 1472 | | // We must keep the colors straight with the point ordering |
| 1473 | | c_min = (p_min == A) ? ca : (p_min == B) ? cb : cc; |
| 1474 | | c_mid = (p_mid == A) ? ca : (p_mid == B) ? cb : cc; |
| 1475 | | c_max = (p_max == A) ? ca : (p_max == B) ? cb : cc; |
| 1476 | | |
| 1477 | | // We must keep the tex coords straight with the point ordering |
| 1478 | | t_min = (p_min == A) ? ta : (p_min == B) ? tb : tc; |
| 1479 | | t_mid = (p_mid == A) ? ta : (p_mid == B) ? tb : tc; |
| 1480 | | t_max = (p_max == A) ? ta : (p_max == B) ? tb : tc; |
| 1481 | | |
| 1482 | | // Find out control points for y, this divides the triangle into upper and lower |
| 1483 | | y_min = (((int)p_min[1]) + 0.5 >= p_min[1]) ? (int)p_min[1] : ((int)p_min[1]) + 1; |
| 1484 | | y_max = (((int)p_max[1]) + 0.5 < p_max[1]) ? (int)p_max[1] : ((int)p_max[1]) - 1; |
| 1485 | | y_mid = (((int)p_mid[1]) + 0.5 >= p_mid[1]) ? (int)p_mid[1] : ((int)p_mid[1]) + 1; |
| 1486 | | |
| 1487 | | // Compute the slopes of each line, and color this is used to determine the interpolation |
| 1488 | | x1_slope = (p_max[0] - p_min[0]) / (p_max[1] - p_min[1]); |
| 1489 | | x2_slope = (p_mid[0] - p_min[0]) / (p_mid[1] - p_min[1]); |
| 1490 | | z1_slope = (p_max[2] - p_min[2]) / (p_max[1] - p_min[1]); |
| 1491 | | z2_slope = (p_mid[2] - p_min[2]) / (p_mid[1] - p_min[1]); |
| 1492 | | w1_slope = (p_max[3] - p_min[3]) / (p_max[1] - p_min[1]); |
| 1493 | | w2_slope = (p_mid[3] - p_min[3]) / (p_mid[1] - p_min[1]); |
| 1494 | | r1_slope = (c_max[0] - c_min[0]) / (p_max[1] - p_min[1]); |
| 1495 | | r2_slope = (c_mid[0] - c_min[0]) / (p_mid[1] - p_min[1]); |
| 1496 | | g1_slope = (c_max[1] - c_min[1]) / (p_max[1] - p_min[1]); |
| 1497 | | g2_slope = (c_mid[1] - c_min[1]) / (p_mid[1] - p_min[1]); |
| 1498 | | b1_slope = (c_max[2] - c_min[2]) / (p_max[1] - p_min[1]); |
| 1499 | | b2_slope = (c_mid[2] - c_min[2]) / (p_mid[1] - p_min[1]); |
| 1500 | | s1_slope = (t_max[0] - t_min[0]) / (p_max[1] - p_min[1]); |
| 1501 | | s2_slope = (t_mid[0] - t_min[0]) / (p_mid[1] - p_min[1]); |
| 1502 | | t1_slope = (t_max[1] - t_min[1]) / (p_max[1] - p_min[1]); |
| 1503 | | t2_slope = (t_mid[1] - t_min[1]) / (p_mid[1] - p_min[1]); |
| 1504 | | |
| 1505 | | // Compute the t values used in the equation Ax = Ax + (Bx - Ax)*t |
| 1506 | | // We only need one t, because it is only used to compute the start. |
| 1507 | | // Create storage for the interpolated x and z values for both lines |
| 1508 | | // also for the RGB interpolation |
| 1509 | | t = (((float)y_min) + 0.5 - p_min[1]) / (p_max[1] - p_min[1]); |
| 1510 | | x1_interp = p_min[0] + (p_max[0] - p_min[0]) * t; |
| 1511 | | z1_interp = p_min[2] + (p_max[2] - p_min[2]) * t; |
| 1512 | | w1_interp = p_min[3] + (p_max[3] - p_min[3]) * t; |
| 1513 | | r1_interp = c_min[0] + (c_max[0] - c_min[0]) * t; |
| 1514 | | g1_interp = c_min[1] + (c_max[1] - c_min[1]) * t; |
| 1515 | | b1_interp = c_min[2] + (c_max[2] - c_min[2]) * t; |
| 1516 | | s1_interp = t_min[0] + (t_max[0] - t_min[0]) * t; |
| 1517 | | t1_interp = t_min[1] + (t_max[1] - t_min[1]) * t; |
| 1518 | | |
| 1519 | | t = (((float)y_min) + 0.5 - p_min[1]) / (p_mid[1] - p_min[1]); |
| 1520 | | x2_interp = p_min[0] + (p_mid[0] - p_min[0]) * t; |
| 1521 | | z2_interp = p_min[2] + (p_mid[2] - p_min[2]) * t; |
| 1522 | | w2_interp = p_min[3] + (p_mid[3] - p_min[3]) * t; |
| 1523 | | r2_interp = c_min[0] + (c_mid[0] - c_min[0]) * t; |
| 1524 | | g2_interp = c_min[1] + (c_mid[1] - c_min[1]) * t; |
| 1525 | | b2_interp = c_min[2] + (c_mid[2] - c_min[2]) * t; |
| 1526 | | s2_interp = t_min[0] + (t_mid[0] - t_min[0]) * t; |
| 1527 | | t2_interp = t_min[1] + (t_mid[1] - t_min[1]) * t; |
| 1528 | | |
| 1529 | | // First work on the bottom half of the triangle |
| 1530 | | // I'm using y_min as the incrementer because it saves space and we don't need it anymore |
| 1531 | | for (; y_min < y_mid; y_min++) { |
| 1532 | | // We always want to fill left to right, so we have 2 main cases |
| 1533 | | // Compute the integer starting and ending points and the appropriate z by |
| 1534 | | // interpolating. Remember the pixels are in the middle of the grid, i.e. (0.5,0.5,0.5) |
| 1535 | | if (x1_interp < x2_interp) { |
| 1536 | | x_start = ((((int)x1_interp) + 0.5) >= x1_interp) ? (int)x1_interp : ((int)x1_interp) + 1; |
| 1537 | | x_end = ((((int)x2_interp) + 0.5) < x2_interp) ? (int)x2_interp : ((int)x2_interp) - 1; |
| 1538 | | z_delta_x = (z2_interp - z1_interp) / (x2_interp - x1_interp); |
| 1539 | | w_delta_x = (w2_interp - w1_interp) / (x2_interp - x1_interp); |
| 1540 | | r_delta_x = (r2_interp - r1_interp) / (x2_interp - x1_interp); |
| 1541 | | g_delta_x = (g2_interp - g1_interp) / (x2_interp - x1_interp); |
| 1542 | | b_delta_x = (b2_interp - b1_interp) / (x2_interp - x1_interp); |
| 1543 | | s_delta_x = (s2_interp - s1_interp) / (x2_interp - x1_interp); |
| 1544 | | t_delta_x = (t2_interp - t1_interp) / (x2_interp - x1_interp); |
| 1545 | | t = (x_start + 0.5 - x1_interp) / (x2_interp - x1_interp); |
| 1546 | | z_interp_x = z1_interp + (z2_interp - z1_interp) * t; |
| 1547 | | w_interp_x = w1_interp + (w2_interp - w1_interp) * t; |
| 1548 | | r_interp_x = r1_interp + (r2_interp - r1_interp) * t; |
| 1549 | | g_interp_x = g1_interp + (g2_interp - g1_interp) * t; |
| 1550 | | b_interp_x = b1_interp + (b2_interp - b1_interp) * t; |
| 1551 | | s_interp_x = s1_interp + (s2_interp - s1_interp) * t; |
| 1552 | | t_interp_x = t1_interp + (t2_interp - t1_interp) * t; |
| 1553 | | |
| 1554 | | } else { |
| 1555 | | x_start = ((((int)x2_interp) + 0.5) >= x2_interp) ? (int)x2_interp : ((int)x2_interp) + 1; |
| 1556 | | x_end = ((((int)x1_interp) + 0.5) < x1_interp) ? (int)x1_interp : ((int)x1_interp) - 1; |
| 1557 | | z_delta_x = (z1_interp - z2_interp) / (x1_interp - x2_interp); |
| 1558 | | w_delta_x = (w1_interp - w2_interp) / (x1_interp - x2_interp); |
| 1559 | | r_delta_x = (r1_interp - r2_interp) / (x1_interp - x2_interp); |
| 1560 | | g_delta_x = (g1_interp - g2_interp) / (x1_interp - x2_interp); |
| 1561 | | b_delta_x = (b1_interp - b2_interp) / (x1_interp - x2_interp); |
| 1562 | | s_delta_x = (s1_interp - s2_interp) / (x1_interp - x2_interp); |
| 1563 | | t_delta_x = (t1_interp - t2_interp) / (x1_interp - x2_interp); |
| 1564 | | t = (x_start + 0.5 - x2_interp) / (x1_interp - x2_interp); |
| 1565 | | z_interp_x = z2_interp + (z1_interp - z2_interp) * t; |
| 1566 | | w_interp_x = w2_interp + (w1_interp - w2_interp) * t; |
| 1567 | | r_interp_x = r2_interp + (r1_interp - r2_interp) * t; |
| 1568 | | g_interp_x = g2_interp + (g1_interp - g2_interp) * t; |
| 1569 | | b_interp_x = b2_interp + (b1_interp - b2_interp) * t; |
| 1570 | | s_interp_x = s2_interp + (s1_interp - s2_interp) * t; |
| 1571 | | t_interp_x = t2_interp + (t1_interp - t2_interp) * t; |
| 1572 | | } |
| 1573 | | |
| 1574 | | // Pass the horizontal line to the filler, this could be put in the routine |
| 1575 | | // then interpolate for the next values of x and z |
| 1576 | | FillSmoothTexPCHorizontalLine( prOptions, |
| 1577 | | x_start, x_end, y_min, z_interp_x, z_delta_x, w_interp_x, w_delta_x, |
| 1578 | | r_interp_x, r_delta_x, g_interp_x, g_delta_x, b_interp_x, b_delta_x, |
| 1579 | | s_interp_x, s_delta_x, t_interp_x, t_delta_x); |
| 1580 | | x1_interp += x1_slope; z1_interp += z1_slope; |
| 1581 | | x2_interp += x2_slope; z2_interp += z2_slope; |
| 1582 | | r1_interp += r1_slope; r2_interp += r2_slope; |
| 1583 | | g1_interp += g1_slope; g2_interp += g2_slope; |
| 1584 | | b1_interp += b1_slope; b2_interp += b2_slope; |
| 1585 | | w1_interp += w1_slope; w2_interp += w2_slope; |
| 1586 | | s1_interp += s1_slope; s2_interp += s2_slope; |
| 1587 | | t1_interp += t1_slope; t2_interp += t2_slope; |
| 1588 | | } |
| 1589 | | |
| 1590 | | // Now do the same thing for the top half of the triangle. |
| 1591 | | // We only need to recompute the x2 line because it changes at the midpoint |
| 1592 | | x2_slope = (p_max[0] - p_mid[0]) / (p_max[1] - p_mid[1]); |
| 1593 | | z2_slope = (p_max[2] - p_mid[2]) / (p_max[1] - p_mid[1]); |
| 1594 | | w2_slope = (p_max[3] - p_mid[3]) / (p_max[1] - p_mid[1]); |
| 1595 | | r2_slope = (c_max[0] - c_mid[0]) / (p_max[1] - p_mid[1]); |
| 1596 | | g2_slope = (c_max[1] - c_mid[1]) / (p_max[1] - p_mid[1]); |
| 1597 | | b2_slope = (c_max[2] - c_mid[2]) / (p_max[1] - p_mid[1]); |
| 1598 | | s2_slope = (t_max[0] - t_mid[0]) / (p_max[1] - p_mid[1]); |
| 1599 | | t2_slope = (t_max[1] - t_mid[1]) / (p_max[1] - p_mid[1]); |
| 1600 | | |
| 1601 | | t = (((float)y_mid) + 0.5 - p_mid[1]) / (p_max[1] - p_mid[1]); |
| 1602 | | x2_interp = p_mid[0] + (p_max[0] - p_mid[0]) * t; |
| 1603 | | z2_interp = p_mid[2] + (p_max[2] - p_mid[2]) * t; |
| 1604 | | w2_interp = p_mid[3] + (p_max[3] - p_mid[3]) * t; |
| 1605 | | r2_interp = c_mid[0] + (c_max[0] - c_mid[0]) * t; |
| 1606 | | g2_interp = c_mid[1] + (c_max[1] - c_mid[1]) * t; |
| 1607 | | b2_interp = c_mid[2] + (c_max[2] - c_mid[2]) * t; |
| 1608 | | s2_interp = t_mid[0] + (t_max[0] - t_mid[0]) * t; |
| 1609 | | t2_interp = t_mid[1] + (t_max[1] - t_mid[1]) * t; |
| 1610 | | |
| 1611 | | // We've seen this loop before haven't we? |
| 1612 | | // I'm using y_mid as the incrementer because it saves space and we don't need it anymore |
| 1613 | | for (; y_mid <= y_max; y_mid++) { |
| 1614 | | if (x1_interp < x2_interp) { |
| 1615 | | x_start = ((((int)x1_interp) + 0.5) >= x1_interp) ? (int)x1_interp : ((int)x1_interp) + 1; |
| 1616 | | x_end = ((((int)x2_interp) + 0.5) < x2_interp) ? (int)x2_interp : ((int)x2_interp) - 1; |
| 1617 | | z_delta_x = (z2_interp - z1_interp) / (x2_interp - x1_interp); |
| 1618 | | w_delta_x = (w2_interp - w1_interp) / (x2_interp - x1_interp); |
| 1619 | | r_delta_x = (r2_interp - r1_interp) / (x2_interp - x1_interp); |
| 1620 | | g_delta_x = (g2_interp - g1_interp) / (x2_interp - x1_interp); |
| 1621 | | b_delta_x = (b2_interp - b1_interp) / (x2_interp - x1_interp); |
| 1622 | | s_delta_x = (s2_interp - s1_interp) / (x2_interp - x1_interp); |
| 1623 | | t_delta_x = (t2_interp - t1_interp) / (x2_interp - x1_interp); |
| 1624 | | t = (x_start + 0.5 - x1_interp) / (x2_interp - x1_interp); |
| 1625 | | z_interp_x = z1_interp + (z2_interp - z1_interp) * t; |
| 1626 | | w_interp_x = w1_interp + (w2_interp - w1_interp) * t; |
| 1627 | | r_interp_x = r1_interp + (r2_interp - r1_interp) * t; |
| 1628 | | g_interp_x = g1_interp + (g2_interp - g1_interp) * t; |
| 1629 | | b_interp_x = b1_interp + (b2_interp - b1_interp) * t; |
| 1630 | | s_interp_x = s1_interp + (s2_interp - s1_interp) * t; |
| 1631 | | t_interp_x = t1_interp + (t2_interp - t1_interp) * t; |
| 1632 | | |
| 1633 | | } else { |
| 1634 | | x_start = ((((int)x2_interp) + 0.5) >= x2_interp) ? (int)x2_interp : ((int)x2_interp) + 1; |
| 1635 | | x_end = ((((int)x1_interp) + 0.5) < x1_interp) ? (int)x1_interp : ((int)x1_interp) - 1; |
| 1636 | | z_delta_x = (z1_interp - z2_interp) / (x1_interp - x2_interp); |
| 1637 | | w_delta_x = (w1_interp - w2_interp) / (x1_interp - x2_interp); |
| 1638 | | r_delta_x = (r1_interp - r2_interp) / (x1_interp - x2_interp); |
| 1639 | | g_delta_x = (g1_interp - g2_interp) / (x1_interp - x2_interp); |
| 1640 | | b_delta_x = (b1_interp - b2_interp) / (x1_interp - x2_interp); |
| 1641 | | s_delta_x = (s1_interp - s2_interp) / (x1_interp - x2_interp); |
| 1642 | | t_delta_x = (t1_interp - t2_interp) / (x1_interp - x2_interp); |
| 1643 | | t = (x_start + 0.5 - x2_interp) / (x1_interp - x2_interp); |
| 1644 | | z_interp_x = z2_interp + (z1_interp - z2_interp) * t; |
| 1645 | | w_interp_x = w2_interp + (w1_interp - w2_interp) * t; |
| 1646 | | r_interp_x = r2_interp + (r1_interp - r2_interp) * t; |
| 1647 | | g_interp_x = g2_interp + (g1_interp - g2_interp) * t; |
| 1648 | | b_interp_x = b2_interp + (b1_interp - b2_interp) * t; |
| 1649 | | s_interp_x = s2_interp + (s1_interp - s2_interp) * t; |
| 1650 | | t_interp_x = t2_interp + (t1_interp - t2_interp) * t; |
| 1651 | | } |
| 1652 | | |
| 1653 | | // Pass the horizontal line to the filler, this could be put in the routine |
| 1654 | | // then interpolate for the next values of x and z |
| 1655 | | FillSmoothTexPCHorizontalLine( prOptions, |
| 1656 | | x_start, x_end, y_mid, z_interp_x, z_delta_x, w_interp_x, w_delta_x, |
| 1657 | | r_interp_x, r_delta_x, g_interp_x, g_delta_x, b_interp_x, b_delta_x, |
| 1658 | | s_interp_x, s_delta_x, t_interp_x, t_delta_x); |
| 1659 | | x1_interp += x1_slope; z1_interp += z1_slope; |
| 1660 | | x2_interp += x2_slope; z2_interp += z2_slope; |
| 1661 | | r1_interp += r1_slope; r2_interp += r2_slope; |
| 1662 | | g1_interp += g1_slope; g2_interp += g2_slope; |
| 1663 | | b1_interp += b1_slope; b2_interp += b2_slope; |
| 1664 | | w1_interp += w1_slope; w2_interp += w2_slope; |
| 1665 | | s1_interp += s1_slope; s2_interp += s2_slope; |
| 1666 | | t1_interp += t1_slope; t2_interp += t2_slope; |
| 1667 | | } |
| 1343 | z += dz; |
| 1344 | w += dw; |
| 1345 | lightR += dlightR; |
| 1346 | lightG += dlightG; |
| 1347 | lightB += dlightB; |
| 1348 | s += ds; |
| 1349 | t += dt; |
| 1350 | |
| 1351 | colorBuffer++; |
| 1352 | depthBuffer++; |
| 1353 | } |
| 1668 | 1354 | } |
| 1669 | 1355 | |
| 1670 | | void hng64_state::drawShaded( struct polygon *p) |
| 1356 | void hng64_poly_renderer::drawShaded(struct polygon *p) |
| 1671 | 1357 | { |
| 1358 | // Polygon information for the rasterizer |
| 1359 | hng64_poly_data rOptions; |
| 1360 | rOptions.texType = p->texType; |
| 1361 | rOptions.texIndex = p->texIndex; |
| 1362 | rOptions.palOffset = p->palOffset; |
| 1363 | rOptions.palPageSize = p->palPageSize; |
| 1364 | rOptions.debugColor = p->debugColor; |
| 1365 | rOptions.texPageSmall = p->texPageSmall; |
| 1366 | rOptions.texPageHorizOffset = p->texPageHorizOffset; |
| 1367 | rOptions.texPageVertOffset = p->texPageVertOffset; |
| 1368 | |
| 1672 | 1369 | // The perspective-correct texture divide... |
| 1673 | | // !!! There is a very good chance the HNG64 hardware does not do perspective-correct texture-mapping !!! |
| 1674 | | int j; |
| 1675 | | for (j = 0; j < p->n; j++) |
| 1370 | // NOTE: There is a very good chance the HNG64 hardware does not do perspective-correct texture-mapping - explore |
| 1371 | for (int j = 0; j < p->n; j++) |
| 1676 | 1372 | { |
| 1677 | 1373 | p->vert[j].clipCoords[3] = 1.0f / p->vert[j].clipCoords[3]; |
| 1678 | 1374 | p->vert[j].light[0] = p->vert[j].light[0] * p->vert[j].clipCoords[3]; |
| r249156 | r249157 | |
| 1682 | 1378 | p->vert[j].texCoords[1] = p->vert[j].texCoords[1] * p->vert[j].clipCoords[3]; |
| 1683 | 1379 | } |
| 1684 | 1380 | |
| 1685 | | // Set up the struct that will pass the polygon's options around. |
| 1686 | | polygonRasterOptions prOptions; |
| 1687 | | prOptions.texType = p->texType; |
| 1688 | | prOptions.texIndex = p->texIndex; |
| 1689 | | prOptions.palOffset = p->palOffset; |
| 1690 | | prOptions.palPageSize = p->palPageSize; |
| 1691 | | prOptions.debugColor = p->debugColor; |
| 1692 | | prOptions.texPageSmall = p->texPageSmall; |
| 1693 | | prOptions.texPageHorizOffset = p->texPageHorizOffset; |
| 1694 | | prOptions.texPageVertOffset = p->texPageVertOffset; |
| 1695 | | |
| 1696 | | for (j = 1; j < p->n-1; j++) |
| 1381 | // Rasterize the triangles |
| 1382 | for (int j = 1; j < p->n-1; j++) |
| 1697 | 1383 | { |
| 1698 | | RasterizeTriangle_SMOOTH_TEX_PC( |
| 1699 | | p->vert[0].clipCoords, p->vert[j].clipCoords, p->vert[j+1].clipCoords, |
| 1700 | | p->vert[0].light, p->vert[j].light, p->vert[j+1].light, |
| 1701 | | p->vert[0].texCoords, p->vert[j].texCoords, p->vert[j+1].texCoords, |
| 1702 | | prOptions); |
| 1384 | // Build some MAME rasterizer vertices from the hng64 vertices |
| 1385 | vertex_t pVert[3]; |
| 1386 | |
| 1387 | const polyVert& pv0 = p->vert[0]; |
| 1388 | pVert[0].x = pv0.clipCoords[0]; |
| 1389 | pVert[0].y = pv0.clipCoords[1]; |
| 1390 | pVert[0].p[0] = pv0.clipCoords[2]; |
| 1391 | pVert[0].p[1] = pv0.clipCoords[3]; |
| 1392 | pVert[0].p[2] = pv0.light[0]; |
| 1393 | pVert[0].p[3] = pv0.light[1]; |
| 1394 | pVert[0].p[4] = pv0.light[2]; |
| 1395 | pVert[0].p[5] = pv0.texCoords[0]; |
| 1396 | pVert[0].p[6] = pv0.texCoords[1]; |
| 1397 | |
| 1398 | const polyVert& pvj = p->vert[j]; |
| 1399 | pVert[1].x = pvj.clipCoords[0]; |
| 1400 | pVert[1].y = pvj.clipCoords[1]; |
| 1401 | pVert[1].p[0] = pvj.clipCoords[2]; |
| 1402 | pVert[1].p[1] = pvj.clipCoords[3]; |
| 1403 | pVert[1].p[2] = pvj.light[0]; |
| 1404 | pVert[1].p[3] = pvj.light[1]; |
| 1405 | pVert[1].p[4] = pvj.light[2]; |
| 1406 | pVert[1].p[5] = pvj.texCoords[0]; |
| 1407 | pVert[1].p[6] = pvj.texCoords[1]; |
| 1408 | |
| 1409 | const polyVert& pvjp1 = p->vert[j+1]; |
| 1410 | pVert[2].x = pvjp1.clipCoords[0]; |
| 1411 | pVert[2].y = pvjp1.clipCoords[1]; |
| 1412 | pVert[2].p[0] = pvjp1.clipCoords[2]; |
| 1413 | pVert[2].p[1] = pvjp1.clipCoords[3]; |
| 1414 | pVert[2].p[2] = pvjp1.light[0]; |
| 1415 | pVert[2].p[3] = pvjp1.light[1]; |
| 1416 | pVert[2].p[4] = pvjp1.light[2]; |
| 1417 | pVert[2].p[5] = pvjp1.texCoords[0]; |
| 1418 | pVert[2].p[6] = pvjp1.texCoords[1]; |
| 1419 | |
| 1420 | // Pass the render data into the rasterizer |
| 1421 | hng64_poly_data& renderData = object_data_alloc(); |
| 1422 | renderData = rOptions; |
| 1423 | |
| 1424 | const rectangle& visibleArea = m_state.m_screen->visible_area(); |
| 1425 | render_triangle(visibleArea, render_delegate(FUNC(hng64_poly_renderer::render_scanline), this), 7, pVert[0], pVert[1], pVert[2]); |
| 1703 | 1426 | } |
| 1704 | 1427 | } |
trunk/src/mess/drivers/segapico.c
| r249156 | r249157 | |
| 119 | 119 | |
| 120 | 120 | #include "emu.h" |
| 121 | 121 | #include "includes/md_cons.h" |
| 122 | | #include "sound/315-5641.h" |
| 122 | #include "sound/upd7759.h" |
| 123 | 123 | |
| 124 | 124 | |
| 125 | 125 | #define PICO_PENX 1 |
| r249156 | r249157 | |
| 130 | 130 | public: |
| 131 | 131 | pico_base_state(const machine_config &mconfig, device_type type, const char *tag) |
| 132 | 132 | : md_cons_state(mconfig, type, tag), |
| 133 | | m_sega_315_5641_pcm(*this, "315_5641"), |
| 133 | m_upd7759(*this, "7759"), |
| 134 | 134 | m_io_page(*this, "PAGE"), |
| 135 | 135 | m_io_pad(*this, "PAD"), |
| 136 | 136 | m_io_penx(*this, "PENX"), |
| 137 | 137 | m_io_peny(*this, "PENY") |
| 138 | 138 | { } |
| 139 | 139 | |
| 140 | | optional_device<sega_315_5641_pcm_device> m_sega_315_5641_pcm; |
| 140 | optional_device<upd7759_device> m_upd7759; |
| 141 | 141 | |
| 142 | 142 | required_ioport m_io_page; |
| 143 | 143 | required_ioport m_io_pad; |
| r249156 | r249157 | |
| 251 | 251 | |
| 252 | 252 | case 8: // toy story 2 checks this for 0x3f (is that 'empty'?) |
| 253 | 253 | /* Returns free bytes left in the PCM FIFO buffer */ |
| 254 | | retdata = m_sega_315_5641_pcm->get_fifo_space(); |
| 254 | retdata = 0x3f; |
| 255 | 255 | break; |
| 256 | 256 | case 9: |
| 257 | 257 | /* |
| 258 | 258 | For reads, if bit 15 is cleared, it means PCM is 'busy' or |
| 259 | 259 | something like that, as games sometimes wait for it to become 1. |
| 260 | 260 | */ |
| 261 | | // return (m_upd7759->busy_r()^1) << 15; |
| 262 | | // The BUSY bit stays 1 as long as some PCM sound is playing. |
| 263 | | // SMPS drivers check 800012 [byte] and clear the "prevent music PCM" byte when the READY bit gets set. |
| 264 | | // If this is done incorrectly, the voices in Sonic Gameworld (J) are muted by the music's PCM drums. |
| 265 | | return m_sega_315_5641_pcm->busy_r() << 15; |
| 261 | return (m_upd7759->busy_r()^1) << 15; |
| 266 | 262 | |
| 267 | 263 | |
| 268 | 264 | case 7: |
| r249156 | r249157 | |
| 283 | 279 | WRITE_LINE_MEMBER(pico_base_state::sound_cause_irq) |
| 284 | 280 | { |
| 285 | 281 | // printf("sound irq\n"); |
| 286 | | /* sega_315_5641_pcm callback */ |
| 282 | /* upd7759 callback */ |
| 287 | 283 | m_maincpu->set_input_line(3, HOLD_LINE); |
| 288 | 284 | } |
| 289 | 285 | |
| r249156 | r249157 | |
| 293 | 289 | |
| 294 | 290 | switch (offset) |
| 295 | 291 | { |
| 296 | | case 0x10/2: |
| 297 | | if (mem_mask & 0xFF00) |
| 298 | | m_sega_315_5641_pcm->port_w(space, 0, (data >> 8) & 0xFF); |
| 299 | | if (mem_mask & 0x00FF) |
| 300 | | m_sega_315_5641_pcm->port_w(space, 0, (data >> 0) & 0xFF); |
| 301 | | break; |
| 302 | | case 0x12/2: // guess |
| 303 | | // Note about uPD7759 lines: |
| 304 | | // reset line: 1 - normal, 1->0 - reset chip, 0 - playback disabled |
| 305 | | // start line: 0->1 - start playback |
| 306 | | if (mem_mask & 0xFF00) |
| 307 | | { |
| 308 | | // I assume that: |
| 309 | | // value 8000 resets the FIFO? (always used with low reset line) |
| 310 | | // value 0800 maps to the uPD7759's reset line (0 = reset, 1 = normal) |
| 311 | | // value 4000 maps to the uPD7759's start line (0->1 = start) |
| 312 | | m_sega_315_5641_pcm->reset_w((data >> 8) & 0x08); |
| 313 | | m_sega_315_5641_pcm->start_w((data >> 8) & 0x40); |
| 314 | | if (data & 0x4000) |
| 315 | | { |
| 316 | | // Somewhere between "Reset Off" and the first sample data, |
| 317 | | // we need to send a few commands to make the sample stream work. |
| 318 | | // Doing that when rising the "start" line seems to work fine. |
| 319 | | m_sega_315_5641_pcm->port_w(space, 0, 0xFF); // "Last Sample" value (must be >= 0x10) |
| 320 | | m_sega_315_5641_pcm->port_w(space, 0, 0x00); // Dummy 1 |
| 321 | | m_sega_315_5641_pcm->port_w(space, 0, 0x00); // Addr MSB |
| 322 | | m_sega_315_5641_pcm->port_w(space, 0, 0x00); // Addr LSB |
| 323 | | } |
| 324 | | } |
| 325 | | |
| 326 | | |
| 327 | | /*m_sega_315_5641_pcm->reset_w(0); |
| 328 | | m_sega_315_5641_pcm->start_w(0); |
| 329 | | m_sega_315_5641_pcm->reset_w(1); |
| 330 | | m_sega_315_5641_pcm->start_w(1); |
| 292 | case 0x12/2: // guess |
| 293 | m_upd7759->reset_w(0); |
| 294 | m_upd7759->start_w(0); |
| 295 | m_upd7759->reset_w(1); |
| 296 | m_upd7759->start_w(1); |
| 331 | 297 | |
| 332 | | if (mem_mask&0x00ff) m_sega_315_5641_pcm->port_w(space,0,data&0xff); |
| 333 | | if (mem_mask&0xff00) m_sega_315_5641_pcm->port_w(space,0,(data>>8)&0xff);*/ |
| 298 | if (mem_mask&0x00ff) m_upd7759->port_w(space,0,data&0xff); |
| 299 | if (mem_mask&0xff00) m_upd7759->port_w(space,0,(data>>8)&0xff); |
| 334 | 300 | |
| 335 | 301 | break; |
| 336 | 302 | } |
| r249156 | r249157 | |
| 390 | 356 | MCFG_CPU_PROGRAM_MAP(pico_mem) |
| 391 | 357 | |
| 392 | 358 | MCFG_DEVICE_REMOVE("genesis_snd_z80") |
| 393 | | MCFG_DEVICE_REMOVE("ymsnd") |
| 394 | 359 | |
| 395 | 360 | MCFG_MACHINE_START_OVERRIDE( pico_state, pico ) |
| 396 | 361 | MCFG_MACHINE_RESET_OVERRIDE( pico_base_state, ms_megadriv ) |
| r249156 | r249157 | |
| 398 | 363 | MCFG_PICO_CARTRIDGE_ADD("picoslot", pico_cart, NULL) |
| 399 | 364 | MCFG_SOFTWARE_LIST_ADD("cart_list","pico") |
| 400 | 365 | |
| 401 | | MCFG_SOUND_ADD("315_5641", SEGA_315_5641_PCM, UPD7759_STANDARD_CLOCK*2) |
| 366 | MCFG_SOUND_ADD("7759", UPD7759, UPD7759_STANDARD_CLOCK) |
| 402 | 367 | MCFG_UPD7759_DRQ_CALLBACK(WRITELINE(pico_state,sound_cause_irq)) |
| 403 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.16) |
| 404 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.16) |
| 368 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.48) |
| 369 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.48) |
| 405 | 370 | MACHINE_CONFIG_END |
| 406 | 371 | |
| 407 | 372 | static MACHINE_CONFIG_START( picopal, pico_state ) |
| r249156 | r249157 | |
| 411 | 376 | MCFG_CPU_PROGRAM_MAP(pico_mem) |
| 412 | 377 | |
| 413 | 378 | MCFG_DEVICE_REMOVE("genesis_snd_z80") |
| 414 | | MCFG_DEVICE_REMOVE("ymsnd") |
| 415 | 379 | |
| 416 | 380 | MCFG_MACHINE_START_OVERRIDE( pico_state, pico ) |
| 417 | 381 | MCFG_MACHINE_RESET_OVERRIDE( pico_base_state, ms_megadriv ) |
| r249156 | r249157 | |
| 419 | 383 | MCFG_PICO_CARTRIDGE_ADD("picoslot", pico_cart, NULL) |
| 420 | 384 | MCFG_SOFTWARE_LIST_ADD("cart_list","pico") |
| 421 | 385 | |
| 422 | | MCFG_SOUND_ADD("315_5641", SEGA_315_5641_PCM, UPD7759_STANDARD_CLOCK*2) |
| 386 | MCFG_SOUND_ADD("7759", UPD7759, UPD7759_STANDARD_CLOCK) |
| 423 | 387 | MCFG_UPD7759_DRQ_CALLBACK(WRITELINE(pico_state,sound_cause_irq)) |
| 424 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.16) |
| 425 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.16) |
| 388 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.48) |
| 389 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.48) |
| 426 | 390 | MACHINE_CONFIG_END |
| 427 | 391 | |
| 428 | 392 | |
| r249156 | r249157 | |
| 588 | 552 | m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0xa15000, 0xa150ff, read16_delegate(FUNC(base_md_cart_slot_device::read_a15),(base_md_cart_slot_device*)m_picocart), write16_delegate(FUNC(base_md_cart_slot_device::write_a15),(base_md_cart_slot_device*)m_picocart)); |
| 589 | 553 | m_maincpu->space(AS_PROGRAM).install_write_handler(0xa14000, 0xa14003, write16_delegate(FUNC(base_md_cart_slot_device::write_tmss_bank),(base_md_cart_slot_device*)m_picocart)); |
| 590 | 554 | |
| 591 | | m_sega_315_5641_pcm->reset_w(0); |
| 592 | | m_sega_315_5641_pcm->start_w(0); |
| 593 | | m_sega_315_5641_pcm->reset_w(1); |
| 594 | | m_sega_315_5641_pcm->start_w(1); |
| 555 | m_upd7759->reset_w(0); |
| 556 | m_upd7759->start_w(0); |
| 557 | m_upd7759->reset_w(1); |
| 558 | m_upd7759->start_w(1); |
| 595 | 559 | |
| 596 | 560 | } |
| 597 | 561 | |
| r249156 | r249157 | |
| 602 | 566 | MCFG_CPU_PROGRAM_MAP(copera_mem) |
| 603 | 567 | |
| 604 | 568 | MCFG_DEVICE_REMOVE("genesis_snd_z80") |
| 605 | | MCFG_DEVICE_REMOVE("ymsnd") |
| 606 | 569 | |
| 607 | 570 | MCFG_MACHINE_START_OVERRIDE( copera_state, copera ) |
| 608 | 571 | MCFG_MACHINE_RESET_OVERRIDE( pico_base_state, ms_megadriv ) |
| r249156 | r249157 | |
| 610 | 573 | MCFG_COPERA_CARTRIDGE_ADD("coperaslot", copera_cart, NULL) |
| 611 | 574 | MCFG_SOFTWARE_LIST_ADD("cart_list","copera") |
| 612 | 575 | |
| 613 | | MCFG_SOUND_ADD("315_5641", SEGA_315_5641_PCM, UPD7759_STANDARD_CLOCK) |
| 576 | MCFG_SOUND_ADD("7759", UPD7759, UPD7759_STANDARD_CLOCK) |
| 614 | 577 | MCFG_UPD7759_DRQ_CALLBACK(WRITELINE(copera_state,sound_cause_irq)) |
| 615 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.16) |
| 616 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.16) |
| 578 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.48) |
| 579 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.48) |
| 617 | 580 | MACHINE_CONFIG_END |
| 618 | 581 | |
| 619 | 582 | |